C陷阱与缺陷 总结

第一章 词法陷阱

= 别写成== 了,同样| &等都要注意。

赋值后,并检查变量是否为零时,要明确写出判断语句,其实是判断语句最好都明确写出来!
if (x = y)
     foo();
应该写为:
if ((x = y) != 0)
     foo();
尽量不要写出:
if (x)
     foo();
把判断都写清楚:
if (x != 0)
     foo();

C编译器词法分析很多采用“大嘴法” (重要)

既是说,读入一个符号后,继续读取下一个符号,如果能和下一个符号一起组成一个有意义的“词组”,那就再继续读取下一个符号,直到没有下一个符号,或者前面的“词组”和下一个符号无法复合出一个有意义的“词组”为止。
举例,a---b,编译器理解的时候,先读一个-,然后看下一个符号还是-,能组成--的“词组”,于是继续读,发现又是个-,而---没有实际意义,于是编译器把上面那句话理解为:(a--) - b
注意:有意义的“词组”中间,是不能加入空格的!上面例子写为 a - - - b,就要报错了。
再举例,y = x/*p    /*p指向除数*/
这个编译器理解的时候,先读/,然后继续读*,得到"词组" /*,发现有意义,再往下读就没符号了,于是把上面的语句理解为 y = x 然后 后面都是注释。
但是!如果加入空格,变成y = x/ *p,编译器就能按照我们想的方式去理解。因为 / 和 * 之间有了空格,就无法组成词组。
注意:上面语句的写法就不好,更好更清楚的应为y = x / (*p);就没烦恼了。
问题:a+++++b怎么解释?
答:( ( a++ ) ++ ) + b。小心为上,感觉面试题会出这么二问题。

整型常量别为了对齐或什么原因,开头乱加个0
举例:
struct {
int part_number;
char *description;
}parttab[] = {
046,    "left-handed   widget"    ,
047,    "right-handed widget"    ,
125,    "frammis"
};
即忘记了整型常量开头加零就成八进制了。
总之就是别粗心,认真第一。

注意字符串和字符区别

printf("Hello world\n");
char hello[] = {'H','e','l','l'……};
printf("%s\n",hello);
显示效果一样,但是显示出来的Hello world存的位置不一样,一个在栈,一个在静态存储区。
作者这里写的printf(hello);但是我自己编译了一下,编译不过去,说hello不是string literal。

单引号相当于整数值  (重要)

int a;
a = "yes";
这是把"yes"字符串所在内 存的首地址,存给了a。
a = 'yes';
赋值后,a的值会因不同的编译器,而有所不同。在Borland下,a = 'y'的值,后续的e s都忽略;而VC和 GCC中,是a = 's' 即一个个覆盖前面一个值。
注意:我写的a = 'y' a = 's' 意思是 y 和 s 的值,不是字符。


第二章 语法陷阱

理解函数声明  (重要)

把变量的类型声明看作两部分,一部分是类型,另一部分是个表达式,对这个表达式求值后,得到的值是前面那类型。
比如:
float f,g;
float就是类型,后面f g就是两个表达式,表达式单独拿出来求值后,值的类型就是float。
同理,float ff();把表达式单独拿出来,ff()求值后,值的类型是float。ff是函数。
float *pf;也可以这么解释其意义。

于是,麻烦点的,float *g(), (*h)();
表达式*g()求值后是个float值,()优先级比*高,所以表达式等效为*(g()),表示g是个函数,g()是执行这个函数后,对返回的值进行解引用,再得到的值是float。即,g是个返回值为指向float类型值的指针。

表达式(*h)()中,*h被()括起来,那先看*h,表示h是个指针,解引用后的值是个函数*h,对这个函数求值(*h)(),再得到的值是个float类型值。即,h是个指向返回值为float类型的函数的指针。

把分号,和变量名去掉,再在外面用括号封装起来,就是类型转换符。
float (*h)();中,h是个指向返回值为float类型的函数指针;则(float (*)())就是“指向返回值为float类型的函数的指针”的类型转换符。

问题:(*(void(*)())0)()是什么意思?
答:首先看最外层,是两个括号(*xxxxx)(),优先级相同,说明这是个求函数指针值的表达式。这个函数指针就是里面那个xxxxx,即(void(*)())0。0是NULL指针,根据上面讲的类型转换符,知道(void(*)())是个类型转换符,给他去掉封装的括号,加上变量名和分号后为:void (*h)(); h是指向返回值为void的函数的指针。

用typedef整理一下就好明白多了:
typedef void (*funcptr)();
(*(funcptr)0)();就是上面那个(*(void(*)())0)()。

不要混合运用算术运算符和逻辑运算符

举例:
r = hi << 4 + low;
如果你想的是先执行hi << 4 ,再执行+ low,那就错了。因为<<比+优先级低。
解决方法两种:
加括号 r = (hi << 4) + low;
纯用逻辑运算符 r = hi << 4 | low ;
第二种方法要好些,因为这里是简单的表达式,复杂一点的话大括号就太乱了。

优先级顺序  (重要)

优先级一般都不要求记忆,也即不住,但大体规律有所了解也是好的。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值