0 简介 1 词法缺陷 1.1 = 不是 == 1.2 & 和 | 不是 && 和 || 1.3 多字符记号 1.4 例外 1.5 字符串和字符 2 句法缺陷 2.1 理解声明 2.2 运算符并不总是具有你所想象的优先级 2.3 看看这些分号! 2.4 switch 语句 2.5 函数调用 2.6 悬挂else 问题 3 连接 3.1 你必须自己检查外部类型 4 语义缺陷 4.1 表达式求值顺序 4.2 &&、||和!运算符 4.3 下标从零开始 4.4 C 并不总是转换实参 4.5 指针不是数组 4.6 避免提喻法 4.7 空指针不是空字符串 4.8 整数溢出 4.9 移位运算符 5 库函数 5.1 getc()返回整数 5.2 缓冲输出和内存分配 6 预处理器 6.1 宏不是函数 6.2 宏不是类型定义 7 可移植性缺陷 7.1 一个名字中都有什么? 7.2 一个整数有多大? 7.3 字符是带符号的还是无符号的? 7.4 右移位是带符号的还是无符号的? 7.5 除法如何舍入? 7.6 一个随机数有多大? 7.7 大小写转换 7.8 先释放,再重新分配 7.9 可移植性问题的一个实例 8 这里是空闲空间 参考 脚注 0 简介 C 语言及其典型实现被设计为能被专家们容易地使用。这门语言简洁并附有表达力。但有一些限制可以保护那些浮躁的人。一个浮躁的人可以从这些条款中获得一些帮助。 在本文中,我们将会看到这些未可知的益处。正是由于它的未可知,我们无法为其进行完全的分类。不过,我们仍然通过研究为了一个 C 程序的运行所需要做的事来做到这些。我们假设读者对 C 语言至少有个粗浅的了解。 第一部分研究了当程序被划分为记号时会发生的问题。第二部分继续研究了当程序的记号被编译器组合为声明、表达式和语句时会出现的问题。第三部分研究了由多个部分组成、分别编译并绑定到一起的 C 程序。第四部分处理了概念上的误解:当一个程序具体执行时会发生的事情。第五部分研究了我们的程序和它们所使用的常用库之间的关系。在第六部分中,我们注意到了我们所写的程序也许并不是我们所运行的程序;预处理器将首先运行。最后,第七部分讨论了可移植性问题:一个能在一个实现中运行的程序无法在另一个实现中运行的原因。 1 词法缺陷 编译器的第一个部分常被称为词法分析器(lexical analyzer)。...