本文是自己读《C陷阱与缺陷》过程中的笔记,内容主要摘自原书
1. 当两个有符号整数运算时,“溢出”有可能发生。
例如:a和b是两个非负整型变量,检查a+b是否会溢出,可以采用如下方式:
ANCI C标准在<limits.h>中定义了INT_MAX。
(1)if ((unsigned)a + (unsigned)b > INT_MAX)
Complain();
(2)if (a > INT_MAX – b)
Complain();
2. 如果一个函数没有float、short、char类型的参数,在函数声明中完全可以省略参数类型的说明,但是函数定义中不能省略参数类型的说明,例如:
double square();
int square(int digit)
{
return 0;
}
如果涉及float、short、char类型参数,声明中没有包含数据类型,float会自动转换为double类型,short或char会自动转换为int类型。
3. C语言规定未定义的标识符后跟一个括号,那么它被视为一个返回整型的函数。例如:
main()
{
double s;
s = sqrt(2);
printf(“%g\n”, s);
}
等同于下面的程序:
extern int sqrt();
main()
{
double s;
s = sqrt(2);
printf(“%g\n”, s);
}
4. 每个外部对象只在一个地方声明,一般在一个头文件中,需要用到该外部对象的所有模块都应该包含这个头文件,定义该外部对象的模块也应该包含这个头文件。
5. Big Endian:最低地址存放高位字节,内存从最低地址开始,按序存放。 Little Endian:最低地址存放低位字节,内存从最低地址开始,按序存放。
所有的处理器都是按Big Endian存放数据的,内存中根据处理器厂商的不同则不同,有Big Endian也有Little Endian。
6. fp = fopen(FILENAME, “r+”);通过r+可进行读写操作,但是一个输入操作不能随后直接跟一个输出操作,反之亦然。如要同时进行输入和输出,必须在其中插入fseek函数的调用。
7. 库函数signal唯一安全、可移植的操作就是打印一条出错信息,然后使用longjmp或exit立即退出程序。
8. 当一个程序异常终止时,程序输出的最后几行常常丢失。这是由于异常终止的程序可能没有机会清空输出缓冲区,生成的输出可能位于内存的某个位置,但却永远不会被写出了,可以通过调用setbuf解决这个问题:
setbuf(stdout, (char *)0);
这个必须在任何输出写入到stdout前执行,最佳位置是作为main函数的第一个语句。
9. 函数调用的开销比宏调用的开销大。某些常用库函数(如:getchar、putchar等)在stdio.h中采用宏实现,同时,在库文件中采用函数形式也进行了实现,因此,不包含stdio.h文件时,对某些常用函数的调用采用的是库文件中的函数调用,导致程序运行效率下降。
10. char c -> (unsigned)c,当把char型字符变量,使用(unsigned)c转换类型,不能得到等价的无符号整数。因为在转换过程中,char型字符变量先被转换成int型整数,此时可能得到非预期结果。
11. 非负数的移位运算相当于除法,负数的移位运算与除法不等效。(-1)>>1的值-1与(-1)/2的值0不同,n > 移位有效值 > 0,n为整数的位数。