丹尼斯·里奇:C如何让Unix可移植
2026年9月9日是丹尼斯·里奇诞辰85周年。他在C和Unix上的工作改变了软件在机器之间迁移的方式,但可移植代码从不意味着每台电脑都能运行同一个文件。

想象把装有你程序的磁盘递给朋友。对方电脑的处理器、操作系统都不同,对文件如何运作也有不同约定。你究竟给了对方什么:能直接运行的东西、能重新构建的东西,还是代价高昂的重写项目?相比罗列那些以某种方式受惠于里奇的知名产品,这个问题更适合介绍他。
海德堡获奖者论坛记载,他出生于1941年9月9日。今天距那一天85年,Nerd Calendar也标记了这个日子。我们在生日提出的问题是:原来的电脑不再存在时,哪些工作仍能保留下来?
C与Unix解决问题的不同部分
C是编程语言,是一种描述操作、让编译器进行翻译的方式。Unix是操作系统,管理资源并向程序提供服务。混淆两者,会遮住它们的关系为何富有成效。语言可以不知磁盘驱动器型号而表达计算;操作系统可以提供文件访问,同时隐藏许多底层机制。
计算机历史博物馆将C的创建归功于里奇,并将Unix的共同创建归功于他和肯·汤普森。其叙述把两者都放在1970年代初的贝尔实验室。这是协作性的系统工作,并非孤独发明家制造计算世界的每一层。
把程序看作三个相连的决定:它应计算什么、如何请求服务,以及由哪些机器指令执行。这些决定可以紧紧纠缠,也可以充分分离,使改变一个不必丢掉另外两个。可移植性始于让这种分离变得有用。
1973年的重写是起点,不是魔法开关
里奇和汤普森的Unix系统论文将用C重写的时间记为1973年夏。存档文本是1974年论文的1978年修订版。它描述了一个虽然体积增长,却更易理解和修改的系统。
用高级语言重写内核,会改变程序员花时间描述的内容。汇编语言紧跟处理器指令;C让程序员描述函数、数据和控制流程,把许多指令层面的选择交给编译器。机器仍然重要,只是主源代码不再需要直接表达那么多例行细节。
可移植性也不是最初的宏大计划。在C语言历史中,里奇说,对可移植性的兴趣来得更晚。C由B演变而来,1972年是最富创造性的一年。这是先改善工作环境,再发现它能够走得更远的故事。
可移植源代码不是万能可执行文件
回到那张磁盘。里面可能是源代码,即用C写成、可阅读的指令;也可能是已经针对特定目标翻译好的可执行文件。这是两种不同礼物。另一目标的编译器可以从合适源代码生成不同机器码。复制旧可执行文件,并不会完成这种翻译。
想象一个读取温度并报告最小值的小程序。比较逻辑无需了解显卡。如果输入输出使用两套系统都有的设施,同一份源代码也许可以分别重新构建。但若使用平台专属图形库加入窗口,那部分就引入了另一项依赖。
编译成功只是一个检查点。程序还需要预期的库、输入约定和行为。能成功打开的文件,数字格式仍可能出乎预料。两个都能启动的程序,仍可能对数据含义理解不同。因此,可移植性需要行为测试,而不只是编译器点头。
硬件变化时,哪些内容必须改变?
阅读程序的一种有用方式,是询问它在哪里对周围环境作出假定。三个地方尤其值得注意:
- 数据表示。程序是否假定某个整数大小,或通过复制原始内存来保存结构体?定义好的交换格式,与内存中的布局是不同事物。
- 操作系统服务。它如何获取文件、时间、输入及其他资源?集中的小接口,比散落在每个函数里的平台调用更容易适配。
- 硬件访问。直接操作设备的代码必须理解该设备。把它放到清晰边界之后,能集中工作,却不会让工作消失。
这些问题是我们实用的阅读框架,并非声称所有老C程序都遵循它。语言提供分离的机会,程序员仍须使用。一个极为紧凑的程序可能充满隐藏假设,略长一点的程序反而可能清楚写出期待。
真正的成就:减少重做人类劳动
在1978年关于C与Unix可移植性的论文中,Stephen C. Johnson和里奇记录了向Interdata 8/32的迁移。实际衡量标准是相对重写节省了多少劳动。大量源代码在不同环境间保持共用,周边工程仍然重要。
这是值得保留的视角。回报不是完全不需要适配,而是保存程序中已经凝结思考的部分:算法、决定和积累的理解。新机器不应自动意味着从头解决同一个问题。
关于史蒂夫·沃兹尼亚克个人电脑工程的文章提供了有用的伴读故事。把两篇作为不同设计问题来读:如何让机器更亲近人,以及如何避免有用软件被困在一台机器里?
生日练习:找出一个隐藏假设
无需移植操作系统,也能尝试这个想法。选一个你理解的小程序,写下预期输入输出,再识别一个关于环境的假设。它可能是目录路径、字符编码,或某个屏幕显示库。
把该假设移到一个命名清楚的边界中。如果有第二套环境,就在那里重新构建,并用相同例子比较结果;如果没有,就记录需要检查什么。这不能证明普遍可移植性,却能把模糊愿望变成别人可以调查的具体问题。
在里奇诞辰85周年,这是一份恰当致敬:让一份知识更容易传递下去。C和Unix没有消除计算机差异,它们的历史说明,降低差异的成本,为何可能比假装差异不存在更重要。
