无意中觅得的好书,这本书总结了很多程序员的错误经验。
词法“陷阱”
编译器中负责将程序分解为一个一个符号的部分,叫“词法分析器”。
1.显示比较。
当需要对变量赋值后,并检查改变量的新值是否为0时,为了避免编译器的警告,我们应该显示的进行比较。
例如:
if(x = y)
fun();
应该写作:
if((x = y) != 0)
fun();
很明显下面的代码意图一目了然。
2.词法分析中的“贪心法”
C语言中的符号,例如/
、*
、=
,只有一个字符长,称为单字符符号。而例如/*
和==
,称为多字符符号。
当C编译器读入字符/
后又跟了一个字符*
,那应该做出判断:是当做两个单独字符,还是合起来当做一个字符对待。
C编译器的解决方法就是“贪心法”,一个一个读入字符,如果能合起来组成一个字符,又继续读,直到读入的字符不可能和之前的字符们组成一个有意义的字符。
需要注意的是,(除了字符串、字符常量)符号的中间不能有空白(空格符、制表符、换行符)。
例如见下面表达式:
a---b 等价于 a -- - b 等价于 (a--)-b
而(上面下面不等价)
a - -- b 等价于 a-(--b)
再例如:
想要表达用x除以p指向的值,再把商赋值给y。
y = x/*p /* p指向除数*/
这个就是错的,编译器会理解成把x赋值给y,它把/*理解为一段注释的开始,并不断读入字符,直到*/出现为止。
y = x / *p /* p指向除数 */
y = x/(*p) /* p指向除数 */
这两种才能正确表达意思。
3.字符与字符串
单引号引起的一个字符代表一个整数,整数值为该字符在编码器中采用的字符集中的序列值。对于采用ASCII字符集的编译器而言,'a'
的含义与97(十进制)或者0141(八进制)完全一致。
双引号引起的字符串,代表的是一个指向无名数组起始字符的指针。该数组被 双引号之间的字符 和 一个额外的二进制为零的字符'\0'
初始化。
printf("Hello \n");
等价于
char h[] = {'H','e','l','l','o',' ','\n','\0'};
printf(h);
等价于
char h[] = {'H','e','l','l','o',' ','\n',0};
printf(h);
因为单引号括起的一个字符代表一个整数,而双引号括起的一个字符代表一个指针,所以不能混用。例如:
char *s = '/';
编译器会报错,因为'/'
只是一个整数,而不是一个指针。
整型数的存储空间存储空间可以容纳多个字符(一般4个,每个占2位),所以C编译器允许在一个字符常量中包括多个字符。例如:'yes'
,在VC++6.0中,编译器一个一个读入字符时,将会依次用后一个字符覆盖前一个字符,最后就得到最后一个字符的整数值。例如下图: