
前 言
对于经验丰富的行家而言,得心应手的工具在初学时的困难程度往往要超过那些容易上手的工具。刚刚接触飞机驾驶的学员,初航时总是谨小慎微,只敢沿着海岸线来回飞行,等他们稍有经验,就会明白这样的飞行其实是一件多么轻松的事。初学骑自行车的新手,可能觉得后轮两侧的辅助轮很有帮助,一旦熟练了,就会发现它们很是碍手碍脚。
这种情况对程序设计语言也是一样。任何一种程序设计语言,总存在一些语言特性,很可能会给还没有完全熟悉它们的人带来麻烦。令人吃惊的是,这些特性虽然因程序设计语言的不同而异,但对于特定的一种语言,几乎每个程序员都在同样的一些特性上犯过错误,吃过苦头!因此,我也就萌生了将这些程序员易犯错误的特性加以收集、整理的最初念头。
我第一次尝试收集这类问题是在1977年。当时,在华盛顿特区举行的一次SHARE(IBM 大型机用户组)会议上,我做了一次题为“PL/I中的问题与‘陷阱’”的发言。做此发言时,我刚从哥伦比亚大学调至AT&T的贝尔实验室。在哥伦比亚大学我们主要的开发语言是PL/I,而贝尔实验室中主要的开发语言却是C。在贝尔实验室工作的10年间,我积累了丰富的经验,深谙C程序员(也包括我本人)在开发时如果一知半解将会遇到多少麻烦。
1985年,我开始收集有关C语言的此类问题,并在年底将结果整理后作为一篇内部论文发表。这篇论文所引发的回应大大出乎我的意料,共有2000多人向贝尔实验室的图书馆索取该论文的副本!我由此确信,有必要进一步扩充该论文的内容,于是就写成了现在读者所看到的这本书。
本书是什么
本书力图通过揭示一般程序员甚至是经验老道的职业程序员如何在编程中犯错误、摔跟头,以提倡和鼓励预防性的程序设计。这些错误实际上一旦被程序员真正认识和理解,并不难避免。因此,本书阐述的重点不是一般原则,而是一个个具体的例子。
如果你是一个程序员并且开发中真正用到C语言来解决复杂问题,本书应该成为你的案头必备图书。即使你已经是一个专家级的C语言程序员,仍然有必要拥有这本书,很多读过本书早期手稿的专业C程序员常常感叹:“就在上星期我还遇到这样一个Bug!”如果你正在教授C语言课程,本书毫无疑问应该成为你向学生推荐的首选补充阅读材料。
本书不是什么
本书不是对C语言的批评。程序员无论使用何种程序设计语言,都有可能遇到麻烦。本书浓缩了作者长达10年的C语言开发经验,集中阐述了C语言中各种问题和“陷阱”,目的是希望程序员读者能够从中吸取我本人以及我所见过的其他人所犯错误的经验教训。
本书不是一本“烹饪菜谱”。我们无法通过详尽的指导说明来完全避免错误。如果可行的话,那么所有的交通事故都可以通过在路旁刷上“小心驾驶”的标语来杜绝。对一般人而言,最有效的学习方式是从感性的、活生生的事例中学习,比如自己的亲身经历或者他人的经验教训。而且,哪怕只是明白了一种特定的错误是如何发生的,就已经在将来避免该错误的路上迈了一大步。
本书并不打算教你如何用C语言编程 (可见Kernighan和Ritchie:The C Programming Language,第2版,Prentice-Hall,1988),也不是一本C语言参考手册(可见Harbison和Steele:C:A Reference Manual,第2版,Prentice-Hall,1987)。本书未提及数据结构与算法(可见Van Wyk:Data Structures And C Programs,Addison-Wesley,1988),仅仅简略介绍了可移植性(可见Horton:How To Write Portable Programs In C,Prentice-Hall,1989)和操作系统接口(可见Kernighan和Pike:The Unix Programming Environment,Prentice-Hall,1984)。本书所涉及的问题均来自编程实践,并适当作了简化(如果希望读到一些“挖空心思”设计出来,专门让你绞尽脑汁的C语言难题,可见Feuer:The C Puzzle Book,Prentice-Hall,1982)。本书既不是一本字典,也不是一本百科全书,我力图使其精简短小,以鼓励读者能够阅读全书。
读者的参与和贡献
可以肯定,我遗漏了某些值得注意的问题。如果你发现了一个C语言问题而本书又未提及,请通过Addison-Wesley出版社与我联系。在本书的下一版中,我很有可能引用你的发现,并且向你致谢。
关于ANSI C
在写作本书时,ANSI C标准尚未最后定案。严格地说,在ANSI委员会完成其工作之前,“ANSI C”的提法从技术上而言是不正确的。而实际上,ANSI标准化工作大体已经尘埃落定,本书提及的有关ANSI C标准内容基本上不可能有所变动。很多C编译器甚至已经实现了ANSI委员会所考虑的对C语言的大部分重大改进。
无须担心你使用的C编译器不支持书中出现的ANSI标准函数语法,它并不会妨碍你理解例子中真正重要的内容,而且书中提及的程序员易犯错误其实与何种版本的C编译器并无太大关系。
致谢
本书中问题的收集整理工作绝非一人之力可以完成。以下诸位都向我指出过C语言中的特定问题,他们是Steve Bellovin(6.3节)、Mark Brader(1.1节)、Luca Cardelli(4.4节)、Larry Cipriani(2.3节)、Guy Harris和Steve Johnson(2.2节)、Phil Karn(2.2节)、Dave Kristol(7.5节)、George W. Leach(1.1节)、Doug McIlroy(2.3节)、Barbara Moo(7.2节)、Rob Pike(1.1节)、Jim Reeds(3.6节)、Dennis Ritchie(2.2节)、Janet Sirkis(5.2节)、Richard Stevens(2.5节)、Bjarne Stroustrup(2.3节)、Ephraim Vishnaic(1.4节),以及一位自愿要求隐去姓名的人(2.3节)。为简短起见,对于同一个问题此处仅仅列出了第一位向我指出该问题的人。我认为这些错误绝不是凭空臆造出来的,而且即使是,我想也没有人愿意承认。至少这些错误我本人几乎都犯过,而且有的还不止犯过一次。
在书稿编辑方面许多有用的建议来自Steve Bellovin、Jim Coplien、Marc Donner、Jon Forrest、Brian Kernighan、Doug McIlroy、Barbara Moo、Rob Murray、Bob Richton、Dennis Ritchie、Jonathan Shapiro,以及一些未透露姓名的审阅人员。Lee McMahon与Ed Sitar为我指出了早期手稿中的许多录入错误,使我避免了一旦成书后将要遇到的很多尴尬。Dave Prosser为我指明了许多ANSI C中的细微之处。Brian Kernighan提供了极有价值的排版工具和帮助。
与Addison-Wesley出版社合作是一件愉快的事情,感谢Jim DeWolf、Mary Dyer、Lorraine Ferrier、Katherine Harutunian、Marshall Henrichs、Debbie Lafferty、Keith Wollman和Helen Wythe。当然,他们也从一些并不为我所知的人那里得到了帮助,使本书最终得以出版,在此一并致谢。
我需要特别感谢AT&T贝尔实验室的管理层,包括Steve Chappell、Bob Factor、Wayne Hunt、Rob Murray、Will Smith、Dan Stanzione和Eric Sumner,他们开明的态度和支持使我得以写作本书。
本书书名受到Robert Sheckley的科幻小说选集的启发,其书名是The People Trap and Other Pitfalls,Snares,Devices and Delusions(as well as Two Sniggles and a Contrivance)(1968年由Dell Books出版)。