C 是世界上最流行的编程语言之一;它最初由 Dennis Ritchie 于 1969 至 1973 年间在 AT&T 贝尔实验室开发。从那时起,成千上万的项目使用 C 开发。它被用于各种应用:操作系统、嵌入式应用、游戏开发、图像处理、文字处理和数据库引擎。
几乎所有其他语言多年来都发生了巨大的演变,但 C 却并非如此;例如,C11 标准并没有给 C 带来多少新特性——只引入了少量修改。
是什么让 C 语言在诞生 50 年后依然如此流行?
一、语言的稳定性
回到 1990 年:Microsoft Word 的早期岁月
那个时代的开发者都记得,当时一台典型的个人电脑可能只有 8 MHz 的处理器、1 MB 内存、20 MB 硬盘和一个软盘驱动器。开发一个文字处理应用是一项巨大的挑战。
微软最近在计算机历史博物馆公布了“Microsoft Word 1.1”的源代码。它的源代码非常值得研究;尽管写于 25 年前,我们仍然可以从中学到一些非常有趣的技术。
下面是它源代码中的一个片段:

可以看到,函数是以 K&R 风格声明的。所有函数都使用同样的风格。
研究“Microsoft Word 1.1”的源文件时,一个有趣的观察是:近期项目中所使用的技术,与“Microsoft Word 1.1”实现中使用的技术并没有太大差异。
让我们以下面的源代码为例:

这段代码看起来像是最近在 GitHub 上创建的 C 项目。没有任何迹象表明它是 25 年前的代码。
1994 年是 Linux 首个版本发布之年
1994 年 3 月 14 日,Linux 1.0.0 发布,但其开发始于 1991 年——感谢 Linus Torvalds 和所有其他贡献者。这第一个版本的源代码可以在这里找到。
下面是 sched.c 源文件中的一个代码片段:

对比研究 Linux 内核第 1 版和最新版本的源文件时,一个令人惊讶的观察是:它们如此相似——风格和所使用的技术都没有重大变化。从一开始,代码就是简单、整洁而质朴的。
二、基本机制
模块化
模块化是一种软件设计技术,它能提高软件由独立部分组成的程度;模块化代码通常更易于管理和维护。
对于 C 这样没有命名空间、组件或类等逻辑机制的过程式语言,我们可以使用目录和文件来进行模块化。
以下是几种可能的做法:
- 把所有源文件放在一个目录里。
- 把与某个模块或子模块相关的文件隔离到特定目录中。
例如,在 Linux 内核中,开发者使用目录和子目录来对内核源代码进行模块化。

封装
封装是指隐藏实现内部的函数和数据。在 C 语言中,封装通过关键字 static 实现。这些实体称为文件作用域的函数和变量。
让我们执行以下CQLinq查询,搜索所有 static 函数。

我们可以使用度量视图来直观地了解有多少函数符合。在度量视图中,代码库以树状图表示。树状图是一种用嵌套矩形展示树形结构数据的方法。CppDepend树状图使用的树结构就是常见的代码层次结构:
- 项目包含目录。
- 目录包含文件。
- 文件包含结构体、函数和变量。
树状图视图为展示 CQLinq 查询结果提供了一种实用的方式,让我们可以直观地看到查询涉及的类型。

可以看到,许多函数都声明为 static。
现在让我们搜索 static 字段:

与函数的情况一样:许多变量都声明为 static。
在 Linux 内核源代码中,只要函数和变量需要在文件作用域内保持私有,就会使用封装。
结语
在简要回顾了一些老牌 C 项目之后,我们可以看到:与现代 C 项目相比,实现技术几乎没有发生变化。
C 的优势之一正是它多年来的稳定性:它始终是一门相对简单的语言,引入的高级机制很少,它的代码直到今天依然直白易懂、易于维护。
