前言
书目信息
书名: Modern C
作者: Jens Gustedt
作者单位: 法国国家信息与自动化研究所(INRIA);法国斯特拉斯堡 ICube 实验室
这是本书第 3 版,定稿于 2024 年 10 月 15 日,与最新的 C 语言标准 C23 保持一致。本书内容与授权给位于美国纽约州谢尔特岛的 Manning Publications Co. 出版的纸质版和电子版相同。
免费版本、示例代码、Manning 纸质版链接及更多资料可在 Modern C 官方网站获取。
© 2016—2024 Jens Gustedt,法国斯特拉斯堡。
许可说明
原稿声明采用“知识共享署名—非商业性使用 4.0 国际”(CC BY-NC 4.0)许可协议。
致谢
特别感谢所有以建设性意见鼓励我完成本书的人,其中包括同事和其他热心读者 Cédric Bastoul、Lucas Nussbaum、Vincent Loechner、Kliment Yanev、Szabolcs Nagy、Marcin Kowalczuk、Ali Asad Lotia、Richard Palme、Yann Barsamian、Fernando Oleo、Róbert Kohányi、Jean-Michel Gorius 和 Martin Uecker;Manning 的工作人员 Jennifer Stout、Nitin Gode 和 Frances Buontempo;以及 Manning 为其经手的两个版本组织的数量可观、令人印象深刻的评审人员。
还有许多人为本书的成功作出了贡献。谨向你们所有人致以最诚挚的谢意。
关于本书
C 程序设计语言诞生于 20 世纪 70 年代初(见 Ritchie [1993])。此后,C 被用于数量惊人的应用之中。个人计算机、手机、相机、机顶盒、冰箱、汽车、大型机和卫星——几乎任何带有可编程接口的现代设备,身边都有用 C 编写的程序与系统。
与 C 程序和系统无处不在的现实相比,真正掌握 C 及其原理的人却少得多。即便是经验丰富的 C 程序员,也常常对 C 语言的现代演进存在某种自己造成的认知停滞。一个可能的原因是,C 被视为一种“容易学习”的语言:经验不多的程序员很快便能写出或复制一些代码片段,而这些代码至少看起来完成了预期工作。从某种意义上说,C 未能激励使用者继续攀登更高的知识层次。
本书旨在改变这种普遍态度,因此按照读者对 C 语言及程序设计的一般熟悉程度划分级别。这种结构可能有悖于部分读者的习惯。特别是,一些困难主题(例如指针)会分散在多个级别中讲解,以免过早塞给读者不合时宜的信息。稍后会更详细地说明全书结构。
本书会介绍许多普遍适用的思想,它们同样适用于 Java、Python、Ruby、C# 和 C++ 等其他程序设计语言;不过,本书主要讨论 C 独有的概念与实践,或者使用 C 编程时格外有价值的概念与实践。
C 的历次修订
正如书名所示,今天的 C 已经不再是其创造者最初设计的那门语言。C 从诞生之初便处在持续调整与改进之中。早期 C 通常称为 K&R C(Kernighan and Ritchie C),名称来自第一本使这门语言广为流行的著作(Kernighan and Ritchie [1978])。此后,C 经历了重要的标准化与扩展过程,如今这一过程由国际标准化组织(ISO)推动,并于 1989、1999、2011、2018 和 2024 年先后发布了一系列 C 标准,通常称为 C89、C99、C11、C17 和 C23。
C 标准委员会为保证向后兼容投入了大量精力,使按较早版本(例如 C11)编写的代码,经实现更新版本的编译器编译后,理应生成语义等价的可执行程序。遗憾的是,这种向后兼容也带来了一项意料之外的副作用:许多本可从新特性中获益良多的项目,缺少更新代码库的动力。为了突出各次修订的进展,本书会标明较新特性由哪个标准版本引入。
本版
本版针对 C 标准的最新修订 C23 进行了大幅改写。书中增加了大量新材料,也梳理了许多原有论述,以体现 C 语言获得的新能力。因此,本书主要讨论 C23 所定义的 C23;但在写作之时,编译器尚未完整实现这项标准。若要编译书中的示例,至少需要一款实现了 C17 大部分内容的编译器。
针对 C23 引入的新内容,本书提供了一个兼容头文件,还会在技术附录中讨论:在 POSIX 系统上,怎样构建一套适用的 C 编译器和 C 库平台作为后备方案。请注意,这并非永久性工具,而只是在各平台完成适配前提供的一根拐杖。
C 与 C++
程序设计已成为极为重要的文化活动和经济活动,C 依然是程序设计世界的重要组成部分。与所有人类活动一样,推动 C 前进的因素很多,包括企业或个人利益、政治、美感、逻辑、运气、无知、自私、自我、宗派观念,以及你愿意填在这里的首要动机。因此,C 的发展历程从来不是、也不可能是理想的。它存在一些缺陷和历史遗留物,只有放到相应的历史与社会背景中才能理解。
C 的发展背景中,一个重要部分是其姊妹语言 C++ 很早便已出现。一种常见误解认为,C++ 是在 C 上不断添加自身特性演化而来的。尽管从历史上说确实如此(C++ 源自非常早期的 C),但这对今天而言并没有多大意义。实际上,C 与 C++ 在 30 多年前便从共同祖先处分道扬镳,此后分别独立演进。不过,两门语言并非与世隔绝地发展;多年来,它们一直相互交换和吸收概念。原子操作与线程等新特性,就是 C 与 C++ 标准委员会密切协作设计的成果。
尽管如此,两者仍有许多差异。本书所讲的内容通常针对 C,而非 C++。许多代码示例甚至无法通过 C++ 编译器编译。因此,不应混用两门语言的资料。
要点 1
C 与 C++ 是不同的语言:不要混用,也不要混淆。
阅读本书时,你还会遇到许多采用这种格式的文字。这些“要点”概括了特性、规则和建议等内容。全书末尾汇集了这些要点,可以把它当作速查表使用。
阅读要求
要从本书中有所收获,需要满足一些最低要求。如果不确定自己是否具备其中某项条件,请先补齐它;否则可能浪费大量时间。
首先,不经实践便无法学会程序设计语言。因此,你必须拥有一个像样的程序设计环境(通常位于个人计算机或笔记本计算机上),并在一定程度上掌握它。这个环境可以是一套集成开发环境(IDE),也可以由彼此独立的工具组成。各平台提供的能力差异很大,很难给出适用于所有人的具体建议。在 Linux 和 Apple macOS 等类 Unix 环境中,可以找到 Emacs、Vim 等编辑器,以及 c99、c17、GCC 和 Clang 等编译器。
你必须能够完成以下工作:
- 浏览文件系统。 计算机上的文件系统通常以目录构成层级结构。你必须能够在这些目录间浏览,找到并处理文件。
- 编辑程序文本。 这不同于在文字处理环境中编辑一封信。无论使用的是何种环境或编辑器,它都应当对 C 语言有基本认识。打开通常以
.c为扩展名的 C 文件时,你会看到它可能突出显示某些关键字,或者根据{}的嵌套层次帮助缩进代码。 - 执行程序。 本书开头出现的程序十分基础,不会提供图形界面。它们需要从命令行启动,编译器就是以这种方式启动的程序之一。在类 Unix 环境中,命令行通常称为 Shell,并在控制台或终端中启动。
- 编译程序文本。 某些环境提供用于编译的菜单按钮或键盘快捷键,也可以在终端的命令行中启动编译器。这款编译器必须符合较新的标准;不要把时间浪费在不符合标准的编译器上。
如果从未编写过程序,本书读起来会很艰难。接触过 Basic、C 的历史版本、C++、Fortran、R、Bash、JavaScript、Java、MATLAB、Perl、Python 或 Scilab 等语言会有所帮助。不过,你也可能拥有其他程序设计经验,只是自己没有意识到。许多技术规范实际上也采用某种专用语言,可以作为类比,例如用于网页的 HTML 和用于文档排版的 LaTeX。
你应当对以下概念有所了解,尽管它们在 C 中的确切含义可能与此前接触的语境略有不同:
- 具名对象: 保存值的具名实体。
- 条件执行: 依照精确条件决定是否完成某项工作。
- 迭代: 将某项工作重复指定次数,或者一直重复到满足某项条件。
源代码
本书给出的许多程序代码片段均已公开发布。你可以结合完整上下文阅读、编译并试验这些代码。代码归档还包含一个 Makefile,其中说明了编译这些文件所需的组件。它主要面向 Linux,或者更一般地说,面向 POSIX 系统;但即使使用其他系统,它也可能帮助你确定所需工具。
练习与挑战
全书各处都安排了练习,目的是促使你思考正在讨论的概念。最好在阅读相应内容时直接完成练习。
另一类任务称为“挑战”。它们通常要求更高:你甚至需要先开展一些调查才能理解问题,而解答也不会凭空出现,必须投入切实努力。它们会占用更多时间,有时是数小时;若对成果要求较高,甚至可能需要数日。这些挑战主题带有作者个人经验形成的“有趣问题”偏好。如果在学习或工作中另有覆盖相同知识的难题或项目,同样可以达到良好效果。重要的是训练自己:先到别处寻找帮助与思路,再亲手实践,把事情真正完成。只有跳进水里,才能学会游泳。
全书结构
本书分为 0 至 3 共四个级别。
起始的第 0 级称为“邂逅”,概述使用 C 编程最基础的知识。它的主要作用是提醒你前面提到的核心概念,使你熟悉 C 特有的词汇和视角。[1] 完成本级后,即便没有太多 C 编程经验,也应当能够理解简单 C 程序的结构,并开始编写自己的程序。
第 1 级“相识”详细介绍控制结构、数据类型、运算符和函数等主要概念与特性。它应当使你更深入地理解程序运行时发生的事情。这些知识足以支持算法入门课程以及同等层次的其他工作,但有一项显著限制:本级尚未完整介绍指针。
第 2 级“相知”深入 C 语言的核心。它会完整讲解指针,使你熟悉 C 的内存模型,并让你能够理解 C 库的大部分接口。完成本级后,应当具备专业编写 C 代码的能力;因此,本级首先会深入讨论 C 程序的编写与组织。作者认为,任何从计算机科学或 C 程序设计相关专业的工程院校毕业的人,都应当掌握这一级的内容。不要满足于更低的标准。
第 3 级“深入”进一步讨论性能、可重入性、原子性、线程和类型泛型编程等特定主题。这些主题最好随着实际需要逐步探索,也就是在现实工作中遇到它们时再学习。不过,从整体上看,它们是圆满完成全书论述、获得完整 C 专业能力所必需的。任何拥有数年 C 专业编程经验的人,或者以 C 为主要程序设计语言的软件项目负责人,都应当掌握这一级的内容。
作者
Jens Gustedt 先后在波恩大学和柏林工业大学完成数学专业学习。当时,他的研究领域涵盖离散数学与高效计算的交叉方向。自 1998 年起,他一直担任法国国家信息与自动化研究所(INRIA)高级研究员,先在南锡的 LORIA 实验室工作;2013 年起转入斯特拉斯堡的 ICube 实验室,并自 2023 年起担任该实验室副主任。
在整个职业生涯中,他的大部分科学研究都伴随着软件开发:早期主要使用 C++,后来则只使用 C。他代表法国标准化协会(AFNOR)担任 ISO JTC1/SC22/WG14 委员会专家,曾任 C17 标准文档以及 C23 初始阶段的共同编辑。他还经营一个颇受欢迎的博客,讨论 C 程序设计及相关主题。
C 的一个特殊视角是,索引从
0开始,而不像 Fortran 那样从1开始。 ↩︎