章节大纲

  • 各版本前言


    第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++标准文档。

    这次我还做了两个重要决定:

    1. 承认可以移植非标准C代码,即使它从未、也永远不会符合C标准;

    2. 提及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语言的一大优势。这正是“严格符合程序”与“符合程序”区别的核心原因之一。