
第一章 C:穿越时空的迷雾

1 p22 ~ 24 ANSI C 有此问题。
“安静”的类型转换原则:当执行算术运算时,操作数的类型如果不同,就会发生转换。数据类型一般朝着浮点精度更高,长度更长的方向转换,整形术如果转换为 singed 不会丢失信息,就转换为 signed,否则转换为 unsigned。
unsinged int a = 1;
int b = -1;
if (b < a) {
printf(“yes \n");
} else {
printf(“no \n”); //运行结果是这个!!!
}
If 语句在 signed 和 unsigned int 之间测试相等性,b 被升级为 unsighed int,因而变成了一个很大的正整数,所以条件为假。如果转换 a 为 int 类型,再比较,不会有问题。
小启发:
尽量不要在你的代码里使用无符号类型,以免增加不必要的复杂性。尤其是,不要仅仅因为无符号数不存在负值(如年龄,国债)而用它来表示数量。
只有在使用位段和二进制掩码的时候,才使用无符号数。应该在表达式中强制类型转换,是操作数同时为有符号数或无符号数,这样就不必由编译器选择结果类型。
第二章 这不是Bug,而是语言特性
1 p40 小启发:x = f() + g() * h(); f,g,h 的计算顺序是不确定的,被称为 意群的计算顺序。这个顺序是未定义的,目的是让编译器充分利用自身架构的特点。编程时,一定不要依赖意群的计算顺序。类似的还有函数中,参数如果是表达式,计算顺序也不确定。
2 p42 用 fgets 取代 gets 函数,由于 gets 没有限制输入的长度,也没有检查,所以很容造成溢出。 fgets 由于限制了长度,可以防止这个问题发生。但标准里没有去掉 gets 方法。
3 p45 shell 或者 C 程序的参数中,要注意 “-” 字符。因为 “-” 往往被理解成参数,例如:“ls -l”。但有时候,你的参数真的只是以 “-” 开头而已,这样却会导致一些错误。比如:grep “-happy”。注意,在运行普通C程序,进行手动参数解析的时候,尤其要注意这一点。
4 p49 由函数的调用者来分配内存,在同一代码块中进行 malloc 和 free 操作,内存管理是最轻松的。
5 p51 尽量使用 lint 程序检查代码。虽然许多人认为应该把 lint 作为一个独立的工具,但是作者认为 独立 = 束之高阁。
第三章 分析 C 语言的声明
1 p58 声明是如何形成的:


2 p63 声明的分析:


一个分析的示例:

对上面解析的一点解释:

3 p68 typedef