《C陷阱与缺陷》----第一章 词法缺陷

本文详细讲解了C语言编译器中词法分析的常见问题,如==与=的区别、&与|与&&与||的混淆、贪心法原则、整型常量的八进制陷阱、字符与字符串的正确使用。通过实例演示和练习,帮助理解编译过程中的符号解析规则。
摘要由CSDN通过智能技术生成

编译器中负责将程序分解为一个一个符号的部分,一般称为“词法分析器”。

编译分为三个阶段预编译,编译,链接。在编译阶段,把C语言代码转换成汇编代码时要用到。

在C语言中,符号之间的空白(包括空格符、制表符或换行符)将被忽略。

1.1 =不同于==

注意:不要把==误用成=,同样也不要把=误用成==。

某些C编译器在发现形如e1=e2的表达式出现在循环语句的条件判断部分时,会给出警告消息以提醒程序员。当确实需要对变量进行赋值并检查该变量的新值是否为0时,为了避免来自该类编译器的警告,我们不应该简单关闭警告选项(通常在表达式的两端添加括号来关闭警告),而应该显式的进行比较。也就是说,下例

if(x = y)
	foo();

应该写作:

if((x = y) != 0)
	foo();

这种写法也使得代码的意图一目了然。

1.2 &和|不同于&&和||

注意:上面的这些符号之间不要进行混淆,因为混淆了编译器常常不会发出任何提示。

1.3 词法分析中的“贪心法”

规则概括:每一个符号应该包含尽可能多的字符。

注意:除了字符串与字符常量,符号的中间不能嵌有空白(空格符、制表符和换行符)。

例如,==是单个符号,而= =则是两个符号,下面的表达式

a---b

与表达式

a -- -b

的含义相同,而与

a - -- b

的含义不同。同样,如果/是为判断下一个符号而读入的第一个字符,而/之后紧接着*,那么无论上下文如何,这两个字符都将被当作一个符号/*,表示一段注释的开始。

例如:

y = x/*p;      //p指向除数

而实际上,/*被理解为一段注释的开始,编译器将不断的读入字符,直到*/出现为止。也就是说,该语句直接将x的值赋给y,根本不会顾及后面出现的p。应该将上面的语句修改为下面的语句才能表达向表达的意思:

y = x/(*p);

1.4 整型常量

0开头的数字被视作八进制数。因此,10与010的含义截然不同。此外,许多C编译器会把8和9也作为八进制数字处理。例如0195的含义是1*82+9*81+5*80,也就是141(十进制)或者0265(八进制)。我们当然不建议这种写法,同时ANSIC标准也禁止这种用法。

注意:有时候,我们在上下文中为了格式对齐的需要,可能无意中将十进制数写成了八进制数。

1.5 字符与字符串

区分’'与""

用单引号引起的一个字符实际上代表一个整数,常常就是其ASCII码值。

用双引号引起的字符串,代表的是一个指向字符串常量区的指针。

如何理解’yes’?

其含义在编译器中没有准去的定义,但大多数编译器理解为:一个整数值,由’y’、‘e’、's’所代表的整数值按照特定编译器实现中定义的方式组合得到。

一般会有三种处理方式:

  1. 忽略多余的字符,最后的整数值即第一个字符的整数值。

  2. 依次用后一个字符覆盖前一个字符,最后得到的整数值即最后一个字符的整数值。VS6.0和GCC v2.95就是这种方式。

  3. 将在’'中的字符按照字节为单位一个个将其填入整型变量所在的内存空间中,下面给出一个例子(编译环境:VS2019)

    #include<stdio.h>
    int main()
    {
    	int a = '1234';
    	printf("%d", a);
    	return 0;
    }
    

    经过调试之后,就可以看到如下所示:

    image-20220301173252546从这就可以看出,在VS2019中是直接将’'中的字符按照字节为单位将其一个 个存入到整型变量所在的内存空间中。

练习

  1. 问:为什么n–>0的含义是n-- >0而不是n- ->0?

    答:根据大嘴法,即每一个符号应该包含尽可能多的字符规则,在编译器读入>之前,就已经将–作为单个符号了。

  2. 问:a+++++b的含义是什么?

    答:上式唯一有意义的解析方式是:

    a ++ + ++ b

    可是,我们也注意到,根据”大嘴法“规则,上式应该被分解为:

    a ++ ++ + b

    这个式子从语法上来说是不正确的,它等价于:

    ((a++)++) +b

    但是,a++的结果不能作为左值,因此编译器不会接收a++作为后面的++运算符的操作数。所以只能被理解为第一种。

评论 64
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鹿九丸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值