第一章:词法陷阱
编译器中负责将程序分解为一个一个符号的部分,一般称为“词法分析器”。例如,对于语句:
if ( x == big ) big = x ;
它的第一个符号是C语言关键字if,紧接着下一个符号是左括号,在下一个符号是标识符x,在下一个是大于号,在下一个是标识符big,以此类推。在C语言中,符号之间的空白(包括空格、制表符、换行符)将被忽略,因此上面的语句还可以写成:
if
(
x
==
big
)
big
=
x
;
这里还需要强调一下“C语言忽略符号间空白”。第一:“符号”的意思并不是“字母”,例如上面的语句中的“==”和“big”,它们都包含了多个字母,但是它们从整体上是一个符号,不可分割。第二:忽略符号与符号之间的空白,意即经过编译器的词法分析之后,符号与符号之间的空白不会被作为一个符号。但是,请注意的是,第二点并不意味着可以乱用空格,例如,在上面的语句中,“==”不可以写做“= =”,如果写成后者,便成了两个赋值号,程序的意思也就变了。
1.1 = 不同于 ==
前者是赋值,后者是判断相等,对于C语言初学者,很容易就犯误用的错误。
1.2 &和|不同于&&和||
前两者是位运算,后两者是关系运算。
1.3 词法分析中的“贪心法”
C语言中的某些符号,例如/、*、和=,只有一个字符,称为单字符符号。而C语言中的其他符号,例如/*和==,以及标识符,包括了多个字符,称为多字符符号。那么当C语言的编译器的词法分析模块读入了一个字符‘/’后又跟了一个字符‘*’,那么编译器就必须做出判断:是将其作为两个分别的符号对待,还是合起来作为一个符号对待。C语言解决这个问题的方案很简单,那就是“贪心法”:每一个符号应该包含尽可能多的字符。
需要注意的是,除了字符串和字符常量,符号的中间不能嵌有空白(空格符、制表符和换行符)。例如,“==”是单个符号,而“= =”则是两个符号。例如下面的表达式:
a---b
那么按照“贪心法”,它的含义是:
(a--) - b
而:
a- --b
的含义是:
a - (--b)
再例如下面的语句,本意似乎是用x除以p所指向的值,把所得的商再赋值给y:
y = x/*p /* p指向除数*/
而实际上,因为“贪心法”,上面语句中的x后面的/*会被C语言词法分析器理解为一段注释的开始。
正确的表达当如下:
y = x/ *p /* p指向除数*/
或者更清楚一点:
y = x/(*p) /* p指向除数*/
1.4整型常量
021不同于21,前者是八进制,后者是十进制。
练习1-1 写一个测试程序,无论是对于允许嵌套注释的编译器还是对不允许嵌套注释的编译器,该程序都能够正常通过编译,但是两种情况下程序的执行结果却不相同。
答案: /*/*/0*/**/1
在允许嵌套注释的情况下,上式值为1;
在不允许嵌套注释的情况下,上式值为0*1;