【C陷阱与缺陷】第1章:词法陷阱解析 | 避开C语言编程的初级坑
在底层的角度下,一个程序就是一个由符号(token)或者记号组成的序列,就像一本书(程序)也只是一个单词(token)序列。还可以把程序看作语句和声明的序列,就像可以把书看作句子的序列一样。把程序分割成符号的过程叫做词法分析。
写作本书的出发点不是要批判C语言,而是帮助C程序员绕过编程过程中的陷阱和障碍。全书分为8章,分别从词法分析、语法语义、连接、库函数、预处理器、可移植性缺陷等几个方面分析了C编程中可能遇到的问题。最后,作者用一章的篇幅给出了若干具有实用价值的建议。
(关注不迷路哈!!!)
文章目录
- 【C陷阱与缺陷】第1章:词法陷阱解析 | 避开C语言编程的初级坑
- 前言
- 一、程序与符号(Token)的基本关系
- 二、常见词法陷阱及实例分析
- 1. 赋值`=`与判等`==`的混淆
- 2. 按位运算符`&`、`|`与逻辑运算符`&&`、`||`的误用
- 3. 词法分析的“贪心法”规则
- 4. 整型常量的八进制陷阱
- 5. 单引号与双引号的区别
- 三、实战练习与思考
- 四、总结与建议
- 五、读后感
前言
- 在C语言编程中,许多看似简单的错误往往源于对词法规则的误解。《C陷阱与缺陷》的第一章深入剖析了这些“词法陷阱”,帮助程序员从底层理解程序符号(token)的组成与解析逻辑。
- 本文基于原书内容整理并扩展,结合实例分析常见问题,为C语言学习者提供实用参考。
一、程序与符号(Token)的基本关系
程序本质上是由符号(token)组成的序列,就像书籍由单词构成一样。词法分析(Lexical Analysis)是将程序拆分为符号的过程。每个符号是一个或多个字符的组合,例如if、(、x等。符号间的空格、换行等不影响解析,但符号本身的组合方式可能导致语义差异。考虑下面的语句:
if(x>big)big=x;// 这个语句中第一个token是if,一个关键字。// 第二个token是左括号,然后是标识符x、大于号、标识符big…// 我们可以在token间添加多余的空格(还有Tab、换行符)等。二、常见词法陷阱及实例分析
1. 赋值=与判等==的混淆
问题:C语言中
=用于赋值,==用于比较。误用可能导致逻辑错误。示例:
while(c=' '||c=='\t'||c=='\n')// 错误:将比较写成了赋值c=getc(f);此处
c = ' '实际是赋值操作,而非比较。由于=优先级低于||,整个表达式变为赋值语句,导致循环无法按预期跳过空白符。修正:明确使用
==进行比较。
2. 按位运算符&、|与逻辑运算符&&、||的误用
区别:
&和|是按位运算符,直接操作二进制位;&&和||是逻辑运算符,返回布尔值(0或1)。
示例:
if(i&j)...// 可能误以为这是逻辑判断,实际是按位与当
i和j非0或1时,结果可能与预期不符。
3. 词法分析的“贪心法”规则
- 规则:编译器从左到右读取字符,尽可能组合最长的有效符号(如
==优先于两个=)。 - 示例:
a---b被解析为(a--) - b,而非a - (--b)。/*被视为注释起始符,导致y = x/*p被误解析为注释(应写为y = x / *p或y = x/(*p))。
- 注意:老版本C编译器可能支持
=+等过时写法,需避免使用。
4. 整型常量的八进制陷阱
规则:以
0开头的数字会被解析为八进制数。示例:
010(八进制)等于十进制8,而非10。0195是非法八进制数(数字9超出八进制范围),可能引发编译器警告。
5. 单引号与双引号的区别
单引号:表示字符常量,实际是整数值(如
'a'在ASCII中为97)。双引号:表示字符串,返回指向字符数组的指针(以
\0结尾)。常见错误:
char*slash='/';// 错误:将整数赋给指针printf('\n');// 错误:参数应为字符串而非字符多字符常量(如
'yes')的行为未定义,应避免使用。
三、实战练习与思考
练习1-1:测试编译器是否支持嵌套注释
/*/**/"*/"/*"/**/- 支持嵌套注释时,输出等效于
"/*"; - 否则输出
"*/"。
- 支持嵌套注释时,输出等效于
练习1-3:为什么
n-->0被解析为n-- > 0?贪心法规则会优先将
--视为一个符号。练习1-4:
a+++++b无法通过编译因为
a++返回的是右值(不可修改),无法再进行++操作。
四、总结与建议
第一章从词法角度揭示了C语言中看似简单却极易出错的细节。这些陷阱不仅是初学者的“拦路虎”,也是资深程序员需持续警惕的问题。通过理解底层规则,我们能更高效地编写可靠代码,避免低级错误。
- 谨慎检查运算符:尤其是
=与==、&与&&等易混淆符号。 - 理解贪心法规则:避免因符号组合导致意外解析。
- 规范常量写法:避免八进制误用,明确单引号与双引号的适用场景。
- 编译器选择:使用现代编译器并开启警告选项(如
-Wall),提前发现潜在问题。
五、读后感
《C陷阱与缺陷》的第一章深入剖析了C语言中的词法陷阱。
- 关于词法陷阱,作者先从区分token与字符开始讲起,进而讲述容易混淆程序员的符号,以便说明“=不同于==”和“& 和 | 不是 && 和 ||”。赋值运算符、比较运算符以及逻辑运算符,有些运算符虽然长得很相似但意义完全不同。
- 文中提到,把程序分割成符号的过程叫做词法分析。作者在第一章中讲述了C语言的词法规则,并且解释了每一个token的形成都是遵循贪心算法策略的。然而,正是由于C语言的词法规则,容易出现一些令人意想不到的问题,比如多个字符组合时哪个优先?字符嵌套如何处理?
- 当然,还有整型常量和单双引号问题,尽管编译后可能不会引发错误,但在运行时可能会产生奇奇怪怪的结果,这些陷阱可能导致的令人困惑的问题。
- 作为本书的阅读者,我深刻认识到C语言编程是一门值得不断学习和钻研的学问。在编程过程中,词法陷阱不仅是我们需要规避的陷阱,更是我们需要探索的宝藏。