简介
章节大纲
-
各版本前言
第1版,1989年(经轻度编辑)
[Howard W. Sams, Hayden Books, ISBN 0-672-48428-5,1989年]
1986年初,我受邀为C语言的可移植性讲授为期三天的研讨会。这个研讨会原本计划在美国多个主要城市举办,虽然最终系列课程被取消,但我已经准备了一份70页的手稿,打算作为讲义使用。
自从我开始接触C语言以来,就一直对它的“双重身份”感到着迷——C既是一种底层的系统实现语言,同时又声称具备可移植性。每当有人兴奋地谈论C语言“本质上的可移植性”时,我总感到不安:要么是我,要么是C语言社区中的相当一部分人忽视了“C语言图景”的某些重要组成部分。结果看来,问题应该不在我。尽管如此,许多写得不错的C代码确实可以相对轻松地进行移植。
由于我既有一份关于可移植性的基础文稿,又对C语言及其标准特别感兴趣,我决定对C语言的可移植性展开正式而深入的研究。同时,由于我长期从事C语言咨询和培训工作,也增强了我将这份为期三天研讨会准备的材料拓展成书籍的决心。过程中我逐渐意识到,这最终的成果值得出版成书。
起初我预计这本书约为200页,后来扩展到300、400,最后定为425页,还是在删减了许多附录的前提下,仅因篇幅限制。而这些“剪辑室地板上的内容”实用性很强,我也在考虑是否通过未来修订版或姊妹篇来发布这些内容。无论如何,这本书并未包含我所有的研究成果。
本书旨在记录在移植现有C代码或编写将要移植到多个目标环境的代码时,可能遇到的C语言特定问题。我说“旨在”是因为本书并不能提供所有答案,很多时候甚至不假装能解决问题。例如,如果你要在不同UNIX版本之间移植代码,本书并不会讨论该操作系统的所有阴暗角落。但我仍认为它是一个可信的起点,为后续作品打下基础。据我所知,这是第一本广泛出版的、专门讨论C语言可移植性、篇幅超过20-30页的书籍。
由于我对3到4个操作系统和硬件环境的了解较为深入,因此本书必然会遗漏某些相关问题;反过来也可能过多地探讨一些仅存在于理论中的晦涩细节。
无论你对可移植性感兴趣的出发点是什么,我都希望本书能给你带来启发——即使它只是帮助你意识到“可移植性并不适合你”,那它也算是大获成功了。反之,如果它能帮助你制定移植策略,或者避免走一些弯路,那我也很欣慰。无论你对本书有何看法,欢迎告诉我。唯有通过建设性的批评、外部意见和持续实践,我才能在未来修订版或姊妹篇中加以改进。
任何写过面向大众的长文档的人都知道:读到第三遍之后,你已经不再“读”你写的内容,而是“看见”你本应写进去的内容。因此,你需要有技术能力的校对者来提供批评性意见。在这方面,以下人士为我校对了全部或大部分手稿,做出了重要贡献:Steve Bartels、Don Bixler、Don Courtney、Dennis Deloria、John Hausman、Bryan Higgs、Gary Jeter、Tom MacDonald 和 Sue Meloy。尽管我采纳了他们许多建议,但因时间和篇幅所限,未能充分利用他们在结构等方面的所有建议。就像软件公司常说的:“我们得给下一版留点内容。”
还有几位对我这段虽短但极其密集的C语言生涯影响深远的人:
-
P.J. Plauger,C标准秘书,ISO C召集人,Whitesmiths Ltd. 总裁;
-
Tom Plum,C标准副主席、Plum Hall 主席、著名C语言作者;
-
Larry Rasler,曾任C标准草案编辑,AT&T C标准委员会代表(现任惠普公司);
-
Jim Brodie,独立顾问(曾在摩托罗拉),自1983年中期起担任C标准委员会主席,并成功主持委员会运作直至1988年左右。
我还要感谢C标准X3J11委员会的各位同仁,有幸与你们合作十分荣幸。没有你们的论文、报告,以及在会议内外的激烈(有时甚至“volatile”)讨论,本书的内容质量和数量都难以达到出版标准。
Rex Jaeschke
第2版,2021年
快进到32年后的今天,C语言世界发生了翻天覆地的变化。尤其值得一提的是:
-
C95、C99、C11 和 C17 标准相继发布;
-
C++ 已成为标准语言,并多次修订;
-
16位系统已近绝迹,甚至32位系统也不再普遍,主流已全面转向64位;
-
不支持C89之前版本的编译器已极少见,但早期代码仍可能在使用。
我进行本次修订的契机来自于我的遗产规划,我问自己:“如果我什么也不做,我的知识产权在我去世后会怎样?”显然,它们将会丢失!因此我决定为这些内容寻找一个公共平台,使其能被阅读,并(希望是负责任地)持续更新。
一旦决定要修订,我就下定决心要狠删内容。(我是《Strunk and White》“少即是多”理念的坚定信徒!)我移除了所有与可移植性无关的内容,删减了大量关于标准库的章节内容。1988年时,第一个C标准即将发布,关于标准库的权威资料匮乏,因此第一版中包含了这些内容。而现在完全没有必要——你可以轻松获取可检索的C和C++标准文档。
这次我还做了两个重要决定:
-
承认可以移植非标准C代码,即使它从未、也永远不会符合C标准;
-
提及C++:C++应用广泛,许多程序员从C++中调用C函数,或者用C++编译器编译C代码。
当然,这一版也终将过时——写作时,C标准委员会正在定稿C23!
第一版中附录列出了按不同方式排列的保留标识符列表。我这次选择不再收录这些内容,原因包括:
-
自C89以来,新增了大量标识符;
-
C23即将发布,更新列表工作量极大;
-
校对者们对列表的呈现方式意见不一,难以兼顾易读性与实用性。
特别感谢以下本版的审阅者:Rajan Bhakta、Jim Brodie、Doug Gwyn、David Keaton、Tom MacDonald、Robert Seacord、Fred Tydeman 和 Willem Wakker。
Rex Jaeschke
本书未来修订方向
更新本书的理由包括:
-
修正拼写或事实错误
-
扩展某些主题
-
增加具体的移植场景、目标硬件和操作系统的细节
-
增加标准C与C++之间的不兼容项
-
涵盖未来版本的C和C++标准
-
扩展与C99及之后版本新增头文件相关的问题,尤其是浮点支持
-
处理与可选IEC 60559(IEEE 754)浮点和复数支持相关的问题
-
增补与可选扩展库有关的问题
-
汇总未定义、不确定、实现定义、本地化相关行为的新实例
-
充实“目标读者”章节
-
考虑发布可下载的保留标识符列表(按头文件和标准版本分类)
对于具体的库函数,若有关于可移植性的评论但本书中尚未收录该函数,需要先创建条目再添加内容。
如您有意参与补充本书,请务必精确,并使用C标准中的术语。所有内容应仅写一次,并在其他地方引用。
目标读者
审阅者 Willem Wakker 写道:
我浏览了整本文档,认为它非常实用。但我不太确定目标读者是谁。您的引言中未提及目标对象。一位经验丰富的C程序员可能会认为:“我已经知道所有技术细节了,不需要这本书。”
实际上,可移植性如同安全性,必须在项目伊始就加以考虑。而在初期阶段,相较于书中详尽的技术细节,更需要的是关于可移植性的整体认知。因此,本书也许应出现在项目中的管理者视野中,由他们“推动”程序员采纳书中的建议。然而,对于这些非技术管理者来说,本书又显得太“技术性”,难以引起他们兴趣。因此,在书前加入几段专门面向管理者、介绍可移植性概念和重要性的内容,也许会是个很好的补充。
我的回应:目前,我将此部分作为占位符添加。但我不会亲自撰写内容,而是留待出版后由读者根据需要自行扩展。
读者预期与建议
本书不教授C语言基础语法,也不讲授C标准。部分段落甚至会像C语言一样“简洁”。虽然我尝试尽可能通俗表达,但仍不为保留的技术性内容道歉。可移植性从不是初学者或实习程序员的关注点——恰恰相反。
本书专注于与语言相关的C代码移植问题。但它不是移植指南,也不提供跨平台移植成功的通用方案,只是详细列出你可能遇到或需要研究的各种问题。本书假定读者已经熟悉C语言的基本结构、运算符、语句、预处理器指令、数据/函数指针及标准运行时库的使用。
C标准及其附带的Rationale文档与本书在结构上保持一致,拥有这两份文件会非常有帮助(虽然不是必需)。不过Rationale写得更通俗,适合非语言学家阅读。值得一提的是,我在1984–1999年间参与了C标准委员会工作,因此本书用语大量借鉴C标准术语。
书中提到“K&R”指的是 Kernighan 和 Ritchie 在1978年出版的《C程序设计语言》第一版。
书中提到的“Standard C”涵盖所有版本,若某特性出自特定版本,则明确注明,如C99。C90只是C89的ISO封装,因此未单独标注。
C标准历史
-
C89:1989年由美国X3J11委员会制定的ANSI标准,首次C语言标准。
-
C90:1990年发布的第一个ISO C标准,与C89技术上等效。
-
C95:1995年对C90的补充修正。
-
C99:第二版ISO C标准,1999年发布。
-
C11:第三版ISO C标准,2011年发布。
-
C17:2018年发布,属于维护版本,无新功能。
-
C23:计划发布的第五版。
关于C++的说明
书中部分段落标注“C++ Consideration”,因为C++被广泛使用,许多程序员从C++调用C函数或用C++编译器编译C代码。但C++并非C的超集,因此理解两者不兼容的地方十分重要。C++标准社区中有句名言:“尽量贴近标准C,但不要更近了!”
可移植性相关术语(摘自C17标准)
-
Unspecified behavior(未指定行为):文档提供多种可能结果,但未规定使用哪一种。
-
Undefined behavior(未定义行为):程序结构或数据错误导致的行为,标准不作要求。
-
Implementation-defined behavior(实现定义行为):各实现需自行说明如何处理的行为。
-
Locale-specific behavior(本地化行为):依赖于国家、文化、语言约定的行为,由实现说明。
尽管本书包含许多此类行为的实例,但完整列表见于C标准的“可移植性问题”附录。
关于“实现依赖”
虽然符合标准的实现必须记录实现定义行为,但本书使用“实现依赖(implementation-dependent)”一词来描述不需要被标准记录的实现特性。
关于“废弃特性”
C89标准曾指出,某些特性为“过时(obsolescent)”,虽因广泛使用而保留,但不建议在新实现或新程序中使用。后来各版本标准通过“弃用(deprecate)”方式正式声明某些特性将逐步移除。
标准委员会宗旨节选
从成立之初,C标准委员会便有一套宗旨,以下条目尤为重要:
-
第2项:C代码应具备可移植性。尽管C语言诞生于UNIX和PDP-11,但它已被广泛应用于各类系统,包括嵌入式系统的交叉编译。
-
第3项:C代码也可以不具备可移植性。标准并不强制程序员编写可移植代码,保留“高级汇编语言”能力是C语言的一大优势。这正是“严格符合程序”与“符合程序”区别的核心原因之一。
-