前 言
C专家编程
C代码。C代码运行。运行码运行…请!
——Barbara Ling
所有的C程序都做同一件事,观察一个字符,然后啥也不干。
——Peter Weinberger
你是否注意到市面上存有大量的C语言编程书籍,它们的书名具有一定的启示性,如:C Traps and Pitfalls(本书中文版《C陷阱与缺陷》已由人民邮电出版社出版), The C Puzzle Book, Obfuscated C and Other Mysteries,而其他的编程语言好像没有这类书。这里有一个很充分的理由!
C语言编程是一项技艺,需要多年历练才能达到较为完善的境界。一个头脑敏捷的人很快就能学会C语言中基础的东西。但要品味出C语言的细微之处,并通过大量编写各种不同程序成为C语言专家,则耗时甚巨。打个比方说,这是在巴黎点一杯咖啡与在地铁里告诉土生土长的巴黎人该在哪里下车之间的差别。本书是一本关于ANSI C编程语言的高级读本。它适用于已经编写过C程序的人,以及那些想迅速获取一些专家观点和技巧的人。
编程专家在多年的实践中建立了自己的技术工具箱,里面是形形色色的习惯用法、代码片段和灵活掌握的技巧。他们站在其他更有经验的同事的肩膀上,或是直接领悟他们的代码,或是在维护其他人的代码时聆听他们的教诲,随着时间的推移,逐步形成了这些东西。另外一种成为C编程高手的途径是自省,在认识错误的过程中进步。几乎每个C语言编程新手都曾犯过下面这样的书写错误:
if(i = 3)
正确的应该是:
if(i == 3)
一旦有过这样的经历,这种痛苦的错误(需要进行比较时误用了赋值符号)一般不会再犯。有些程序员甚至养成了一种习惯,在比较式中先写常数,如:if(3 == i)。这样,如果不小心误用了赋值符号,编译器就会发出“attempted assighnment to literal(试图向常数赋值)”的错误信息。虽然当你比较两个变量时,这种技巧起不了作用。但是,积少成多,如果你一直留心这些小技巧,迟早会对你有所帮助的。
价值2000万美元的Bug
1993年春天,在SunSoft的操作系统开发小组里,我们接到了一个“一级优先”的Bug报告,是一个关于异步I/O库的问题。如果这个Bug不解决,将会使一桩价值2000万美元的硬件产品生意告吹,因为对方需要使用这个库的功能。所以,我们顶着重压寻找这个Bug。经过几次紧张的调试,问题被圈定在下面这条语句上:
x == 2;
这是个打字错误,它的原意是一条赋值语句。程序员的手指放在“=”键上,不小心多按了一下。这条语句成了将x与2进行比较,比较结果是true或者false,然后丢弃这个比较结果。
C语言的表达能力也实在是强,编译器对于“求一个表达式的值,但不使用该值”这样的语句竟然也能接受,并且不发出任何警告,只是简单地把返回结果丢弃。我们不知道是应该为及时找到这个问题的好运气而庆幸,还是应该为这样一个常见的打字错误可能付出高昂的代价而痛心疾首。有些版本的长整数程序已经能够检测到这类问题,但人们很容易忽视这些有用的工具。
本书收集了其他许多有益的故事。它记录了许多经验丰富的程序员的智慧,避免读者再走弯路。当你来到一个看上去很熟的地方,却发现许多角落依然陌生,本书就像是一个细心的向导,帮助你探索这些角落。本书对一些主要话题如声明、数组/指针等作了深入的讨论,同时提供了许多提示和记忆方法。本书从头到尾都采用了ANSI C的术语,在必要时我会用日常用语来诠释。
目 录
第1章 C:穿越时空的迷雾
1.1 C语言的史前阶段
1.2 C语言的早期体验
1.3 标准I/O库和C预处理器
1.4 K&R C
1.5 今日之ANSI C
1.6 它很棒,但它符合标准吗
1.7 编译限制
1.8 ANSI C标准的结构
1.9 阅读ANSI C标准,寻找乐趣和裨益
1.10 “安静的改变”究竟有多少安静
1.11 轻松一下——由编译器定义的Pragmas效果
第2章 这不是Bug,而是语言特性
第3章 分析C语言的声明
第4章 令人震惊的事实:数组和指针并不相同
第5章 对链接的思考
第6章 运动的诗章:运行时数据结构
第7章 对内存的思考
第8章 为什么程序员无法分清万圣节和圣诞节
第9章 再论数组
第10章 再论指针
第11章 你懂得C,所以C++不在话下
附录A 程序员工作面试的秘密
附录B 术语表