回上级页面

2025 年 04 月 14 日


有很多人,认为 C 语言非常落后了,没有这个,没有那个。他们说,那些后来诞生的语言,它们既有这个,又有那个……其中任何一门语言都比 C 语言更现代,更值得学习。

他们的看法实际上是对的,但也是错的。在语言上,他们是对的。在编程上,他们是错的。

C 语言没有面向对象编程,面向接口编程以及函数式编程的语法,也没有异常机制、类型自动推导以及内存自动回收等特性。许多年前,我喜欢与 C++ 语言爱好者争辩,我说 C 语言也能写面向对象程序,有时会以 GObject 库作为论据,而我却一直未能真正学会这个库的用法。这种争辩着实没有任何必要。无论我多么喜欢 C 语言,坦诚而言,C 语言在设计上是落后的。用 C 语言写程序,像是用先秦散文的形式写文章,语言的表现力不足以支撑大规模商业软件开发。

在编程上,C 却比当世任何一门语言都先进。这个角度是最近这两年我才想通的。C 的先进性,通读过 CSAPP 这本书(即《深入理解计算机系统》)的人应该都能有所觉察。C 语言可嵌入汇编语言,它有指针、有线程、有进程,有进程间通信,有套接字函数,有 Win32 API,有 Unix 或 Linux 数百个系统调用,有通用计算机,也有小型嵌入式设备。

C 的先进性,一言蔽之,虚心实腹。

你可能孜孜不倦于探究面向对象领域的各种设计模式,函数式编程领域的范畴论,动态语言五彩缤纷的开发框架,在语言层面上,这些开发范式的主要工作是,提高代码的复用性。软件开发的复杂度,凭借代码复用可以得到降低吗?不完全如此。许多复杂性只是从应用软件开发层面转移到编译器或解释器的开发工作中了,而且语言本身也变得日益复杂……试问,你学得会 C++ 或 Rust 吗?还有 Haskell 呢?

复杂性,从不会消失,它只会转移。

C 语言应对软件开发复杂度的策略一贯是分而治之,将复杂度分割为可控的单元,然后借助线程和进程实现这些单元,再以共享内存、管道或网络套接字等通信机制将这些单元连接为系统。这种应对软件复杂度的策略从 Unix 诞生的时候便已经确立了。网络编程,实际上也是一种深具启发性的编程范式。在网络编程中,时间变成了一种设备,万物并发,物与物之间基于单纯的消息交相协作。这种范式,如正气歌所吟唱的,上则为日星,下则为河岳,而网络编程肇始于 C。

C++ 语言有值得称道的标准模板库,Java 语言有值得称道的内存自动回收机制,go 语言有值得称道的并发特性,rust 语言有值得称道的内存安全性……那么,C 语言为什么不能有值得称道的操作系统里的一切呢?当你用着语法更好的语言,努力描述着计算机世界的存在和风光时,你需要记着,C 语言早已与这个世界浑然一体了。