《C陷阱与缺陷》笔记

时间:2022-12-28 12:20:54

      这本书不是批判,而是指出易犯错误,防止编程中的陷阱和障碍。


1、易犯错误类型归纳:

(1)词法分析;(2)语法细节问题;(3)语义细节;(4)库函数的误用;(5)预处理器;(6)可移植性;(7)预防性程序设计;


2、运算符优先级:

(1)任何一个逻辑运算符的优先级低于任何一个关系运算符;

(2)移位运算符的优先级比算术运算符要低,但是比关系运算符要高;

               例如:r = high << 4 + low;    等价于    r = high << ( 4 + low );

(3)运算符== 和 != 的优先级要低于其他关系运算符;


3、指针与数组:

(1)int calendar [12][31];  ----> calendar是一个有着“12个数组类型元素”的数组,它的每个数组类型元素又是一个有着“31个整型元素“的数组。

(2)int *p;  p = calendar[4];   ----> 指针p指向了数组calendar[4]中下标为0 的元素。

(3)int  i;  i = calendar[4][7];     等价于     i = *( calendar[4] + 7 );      等价于      i = *( ( calendar + 4) + 7 );  

(4)int  (*month)[31];   ----> 声明了 *month 是一个拥有31个整型元素的数组;

(5)month = calendar; ----> month将指向数组calendar的第一个元素,也就是数组calendar数组的12个有着“31个整型元素“的数组类型元素之一;


4、static防止命名冲突:

      我们可以在多个源文件中定义同名的函数wei_global_func(),只要所有的函数wei_global_func()都被定义为static,或者仅仅只有其中一个函数wei_global_func()不是static。也就是说,为了避免可能出现的命名冲突,如果一个函数仅仅被同一个源文件中的其它函数使用,那么我们就应该声明该函数为static。(全局变量亦如此)


5、函数printf 和 scanf:

《C陷阱与缺陷》笔记

        我们希望从标准输入设备读入5个数,在标准输出设备上输出5个数:0 1 2 3 4 5。但是。。。

《C陷阱与缺陷》笔记


6、宏函数:

(1)不能忽视宏定义中的空格:

例如:

     #define  f(x)  ( (x) - 1 )    ----->  f(x)代表( (x) - 1 )  ;

     #define  f  (x)  ( (x) - 1 )    ----->  f(x)代表( x ) ;      注意 f 和 ( x ) 之间有空格!

(2)还要注意宏函数是直接替换!最好在宏定义中把每个参数都用括号括起来,最好也把整个表达式用括号括起来。

例如:

     #define  abs(x) ( ( (x) >= 0 ) ? ( x ) : - ( x ) )

求abs( a - b) 时,((a - b) >  0  ? (a - b) :-(a - b))。正确!

    假设写成: #define  abs(x)   x >= 0  ?  x  : -  x

求abs( a - b) 时,a - b >  0  ? a - b :- a - b。错误!

(3)还要注意宏函数中的++ 和 -- ,在代码中宏函数是直接替换,有可能会++ 和 --好几次(看操作数用到几次)!总之要记住的就是“宏函数是直接替换”。(递增运算符和递减运算符的副作用)

(4)如果宏展开可能产生非常庞大的表达式,占用的空间远远超过了所期望的空间,那么就要弃用宏函数!