《C陷阱与缺陷》第一章心得与笔记 词法陷阱
1.1 =和==
‘=’是赋值运算符;’=='是比较运算符。
eg1:
if (x = y)
本例本想判断x与y是否相等,写成x = y后,if的条件就变成了先将y赋值给x,再判断x的值是否为0。
eg2:
while(c = ' ' || c == '\t' || c == '\n')
{
c = getc(f);
}
本例中循环语句上的本意是跳过文件中的空格符、制表符、和换行符,本想写成c == ‘ ’,结果误写成了c = ’ ‘。由于赋值运算符’=‘的优先级要比逻辑运算符’||‘低,所以,实际上是将一下表达式的值赋值给了c = ’ ’ || c == ‘\t’ || c == ‘\n’,因为 ‘ ’不等于0,(’ '的ASCII码值为32),所以while循环会一直运行,知道文件读取结束。文件读取结束之后循环是否继续,取决于getc库函数的具体实现。
eg3:
if ((filedesc == open(argc[i], 0)) < 0)
error();
在本例中,如果open函数执行成功,将返回0或者正数,如果执行失败,则返回-1。上面的代码本意是将open函数的返回值赋值给filedesc,然后判断filedesc是否小于0。将’=‘误写成’‘之后,则变成了先判断filedesc的值与open函数的返回值是否相等,再判断是否小于0,由于’'的结果只有0或者1,永远不可能小于0,则if的条件恒为1。有些编译器会提示相应的警告。
1.2 & 和 | 不同于 && 和 ||
&:按位与
|:按位或
&&:逻辑与
||:逻辑或
1.3 词法分析中的“贪心法”
C语言编译器判断由多个字符组成的符号的规则:每一个符号应该尽可能的包含更多的字符。
编译器将程序分解成符号的方法是:从左到右一个字符一个字符的读入,如果该字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分;如果可能,继续读入下一个字符,重复上述判断,直到读入的字符串组成的字符串已不再可能组成一个有意义的符号。这个处理过程被称为“贪心法”。
需要注意的是,除了字符串和字符常量,符号的中间不能嵌有空白(空格符、制表符和换行符)。
1.4 整型常量
如果一个整形常量的第一个字符是数字0,那么该常量将被视作八进制数。
1.5 字符与字符串
用单引号引起的一个字符实际上代表一个整数,整数值对应该字符在编译器采用的字符集中的序列值。因此,对于采用ASCII字符集的编译器而言,'a’的含义与0141(八进制)或者97(十进制)严格一致。
用双引号引起的字符串,代表的是一个指向无名数组起始字符的指针,该数组被双引号之间的字符以及一个额外的二进制值为0的字符’\0’初始化。
eg1:
下面语句
printf("Hello world\n");
与
char hello[] = {'H', 'e', 'l', 'l', 'o', ' ',
'w', 'o', 'r', 'l', 'd', '\n', 0};
printf(hello);
是等效的。