《C陷阱与缺陷》是由Andrew Koenig所著,高巍译。Andrew Koenig是AT&T大规模程序研发部(前贝尔实验室)成员,不仅有着多年的C++开发,研究和教学经验,而且还亲身参与了C++的演化和变革,对C++的变化和发展起到重要的影响。
第一章 词法陷阱
编译器中负责将程序分解为一个一个符号的部分,一般称为“语法分析器”。
1.1 = 不同于 ==
while (c=‘‘ || c==‘ ‘ || c==‘ ‘)
c=getc(f);
这个循环将一直进行到文件的结束,是否死循环取决于getc的实现。
如果确实需要在条件判断部分使用赋值,应该显式地进行比较:
if ((x=y) != 0)
foo();
1.2
& 和 | 不同于 && 和 ||
1.3
语法分析中的“贪心法”
C语言对这个问题的解决方案可以归纳为一个很简单的规则:每一个符号应该包含尽可能多的字符。
编译器将程序分解成符号的方法是,从左到右一个字符一个字符地读入,如果该字符可能组成一个符号,再接着读下个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分;如果可能,继续读入下一个字符,重复上述判断,知道读入的字符组成的字符串已不再可能组成一个有意义的符号。这种处理策略有时被称为“贪心法”,或者更口语化一点,称为“大嘴法”。
a---b 与 a -- - b 的含义相同,而与 a - -- b 的含义不同。
1.4 整型常量
如果一个整型常量的第一个字符是数字0,那么该常量将被视作八进制数。
1.5 字符与字符串
C语言中的单引号和双引号含义迥异,在某些情况下如果把两者弄混,编译器并不会检测报错,从而在运行是产生难以预料的结果。
用单引号引起的一个字符实际上代表一个整数,整数值对应于该字符在编译器采用的字符集中的序列值。
用双引号引起的字符串,代表的却是一个指向无名数字起始字符的指针,该数组被双引号之间的字符以及一个额外的二进制为零的字符 ‘\0‘ 初始化。
然而,某些C编译器对函数参数并不进行类型检查,特别是对printf函数的参数。因此, 如果用
printf(‘ ‘); 来代替正确的 printf(" ");
则会在程序运行的时候产生难以预料的错误,而不会给出编译器诊断信息。
整型数(一般为16位或32为)的存储空间可以容纳多个字符(一般为8位),因此有个C编译器允许在一个字符常量(以及字符串常量)中包括多个字符。也就是说,用‘yes‘代替"yes"不会被该编译器检测到。后者的含义是“一次包括‘y‘‘e‘‘s‘以及空字符‘‘的4个连续内存单元的首地址“。前者的含义并没有准确的进行定义,但大多数编译器理解为,“一个整数值,由‘y‘‘e‘‘s‘所代表的整数值按照特定编译器实现中定义的方式组合得到“。
习题:
练习 1-3 为什么 n-- > 0, 而不是 n- ->0?
答:根据词法分析中的“贪心法”,编译器在读取字符的顺序是先读取n ,然后读取 - ,在读取 -,判断出n--组成字符串是一个符号,再读取> 时,不能组成符号,故是n-- > 0, 而不是 n- ->0,注意--之间不能嵌有空白、空格符、制表符和换行符。)
练习 1-4 a+++++b的含义是什么?
答:根据贪婪法匹配原则,它的含义应为 a++ ++ +b,而不是a++ + ++b(可能是合法的)考虑。这是个非法的表达式,因此产生编译错误。这个问题在ISO C99标准中直接以示例描述,原文如下:
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/cowena/article/details/47271521