编辑: 黑豆奇酷 | 2015-08-31 |
big) big = x;
这个语句中第一个token是 if ,一个关键字.第二个token是左括号,然后是标识符 x 、大 于号、标识符 big ……在C中,我们可以在token间添加多余的空格(还有Tab、换行符)等,所 以我们还可以这样写: if ( x >
big ) big = x ;
本章将会探究对于token含义的常见的误解,以及token和组成它的字符间的关系. 第1章 词法陷阱
6 第1章 词法陷阱
7 1.1 = 不是 == 大多数由Algol派生的编程语言,比如Pascal和Ada,都使用 := 表示赋值,用 == 表示判等. 而C语言,是用 = 表示赋值,用 == 表示判等.这确实更方便,因为赋值比判等操作频繁得 多,这样短符号就会用得更多.除此之外,C把赋值作为一种运算符,这样多重赋值(比如 a=b=c )就能很容易地写出来,而且赋值也能被嵌入更大的表达式中. 这种便利也导致了一个潜在的问题:一个人可能不经意地把一个判等写成了赋值.因此下面 的语句,很明显本来想在x等于y时执行break语句: if (x=y) break;
实际上却变成了把y赋值给x然后判断这个值是不是非零.再看下面这个循环,本意是想在读 取文件时跳过空格、tab符、换行符: while (c c == '
\t'
|| c== '
\n'
) c = getc(f);
这个循环在比较空格时错误地使用了 = 而不是 == .因为 = 比 || 优先级低,这个 比较 实 际上把c赋值为下面整个表达式的值: '
'
|| c == '
\t'
|| c == '
\n'
因为'
'
的值是非零的,所以这个表达式实际上把 c 赋值为
1 并把 c 原本的值覆盖了.所以这 个循环是把文件的每一个字符都跳过了.在读取完整个文件之后的操作取决于库的实现是否 允许一个程序在到达文件尾之后继续读取.如果允许,这个循环将无穷无尽地进行下去. 一些C编译器试图通过对形如 e1 = e2 的条件表达式给出警告信息来帮助他们的用户.当对一 个变量赋值并检查这个值是否是0的时候,可以通过将条件表达式表达地更具体来避免在这类 编译器产生警告.换句话说,即把: if (x = y) foo();
写成: if ((x = y) != 0) foo();
1.1 = 不是 ==
8 这也同时使你的意
图表达地更直接.我们会在2.2节(17页)讨论为什么要在 x = y 之外加小括 号. 也有可能会产生另一种相反的混淆: if ((filedesc == open(argv[i], 0)) >
= 1;
不会报错,但 是一个严格的ANSI C编译器会拒绝这种写法. 1.3 词法分析中的贪心法
11 1.3 词法分析中的贪心法
12 1.4 整型常量 如果一个整型常量的第一个数字是0,这个常量就被当作八进制数.那么10和010就会代表完 全不同的两个数.此外,很多C编译器会不加判断地把8和9作为十进制数(8和9不可能是八进 制数).这种奇怪的规定起源于对于八进制数的定义.例如,0195代表 $$18^2+98^1+5*8^0$$,等于十进制的141或者八进制的0215.很明显,我们反对这种用 法.ANSI C也禁止这种用法. 注意像这样的在上下文中对八进制数的粗心使用: struct { int part_number;
char *description;
}parttab[] = { 046, left-hand widget , 047, right-hand widget , 125, frammis };
1.4 整型常量
13 1.5 字符串和字符 单引号和双引号在C语言中代表完全不同的含义,在某些上下文中,把他们搞混了不会产生错 误信息,但是结果会出乎意料. 写一个字符加单引号跟写出这个字符在系统库实现中赋予的整数值是一样的.因此,在ASCII 实现下,'