
最初,我们有Fortran(1957年)、Pascal(1970年)和C(1972年)等编程语言。Fortran专为数值计算和科学计算而设计。Pascal在底层访问方面有所限制(它刻意追求“安全”,旨在用于结构化编程教学)。因此,C最终胜出,因为它既允许底层/不安全的编程(指针运算、直接内存访问),又足够通用,可以用于像Unix这样的系统。公平地说,Pascal也有一些后继语言至今仍在使用,但C显然占据了主导地位。
20世纪80年代和90年代,面向对象编程被视为未来发展方向,并逐渐演变成一种独特的流派。
但 C 语言并非面向对象的。
于是就有了 C++,它最初被称为“带类的 C 语言”。C++ 拥有模板,从而实现了泛型编程和编译时元编程。语言的这一部分使 C++ 功能强大,但也使其难以掌握(而且错误信息也相当复杂)。
C 和 C++ 都取得了巨大的成功,但编写可移植的应用程序仍然很困难——你通常必须针对 Windows 或特定的 Unix 版本。这对于像 Sun Microsystems 这样销售 Unix 系统并希望与当时正在崛起的微软巨头竞争的公司来说,是一个难题。
于是,Java 于 1995 年问世。它被定位为 C++ 的安全、可移植的替代方案:它消除了原始指针运算,增加了强制性垃圾回收,在所有地方都进行了数组边界检查,并且在虚拟机 (JVM) 上运行,通过即时编译来提高性能。
“一次编写,到处运行”的承诺直接解决了 C/C++ 的可移植性难题。时至今日,Java 仍然是编写可移植的企业级和服务器端代码的强大解决方案。
1995年,我们迎来了JavaScript。尽管名字相似,但它在语义上与Java几乎没有任何共同之处。最好将其视为独立于C/C++分支之外的语言。Python的情况也类似,与Java截然不同。
微软最终在2000年推出了C#。它与C++和Java一样,都属于C系列语言的语法传统,但支持现代.NET中的预编译(AET)。它还允许在显式标记为不安全的作用域内进行受保护的指针访问。从某种意义上说,C#可以被视为“带有垃圾回收机制的C++”。凭借Unity引擎,它甚至在游戏行业与C++展开竞争。
谷歌开发了 Go 语言。它很像一个更简单、更现代的 C 语言:有垃圾回收机制,内置切片/数组边界检查,允许使用指针,但在安全代码中不允许任意运算(有 unsafe 包来满足底层需求)。
后来,苹果公司推出了 Swift。它拥有类似 C++ 的性能和语法目标,但增加了现代安全特性(默认进行边界检查,调试模式下会触发整数溢出 panic),并使用自动引用计数 (ARC) 进行内存管理。
大约在同一时间,我们迎来了 Rust。和 Swift 一样,它摒弃了 Java、C# 和 Go 中的分代垃圾回收机制。Rust 转而依赖编译时所有权和借用规则,但缺点是可能会出现循环引用导致的内存泄漏。此外,Zig 也实现了内存使用情况的完全显式化。
我认为将 Rust 和 Zig 描述为 C 的后代比描述为 C++ 的后代更为恰当。当然,它们都比 C 强大得多……而且编程语言的演变过程十分复杂。尽管如此,它们仍然是类似 C 的编程语言。
时至今日,在很多行业领域,对于性能至关重要的系统、企业级应用和基础设施开发而言,C、C++、Java 和 C# 仍然是主流编程语言。根据林迪效应(某种事物存在的时间越长,就越有可能继续存在),这些语言,尤其是已经超过 50 年历史的 C 语言,仍将继续存在很长时间。
原文: https://lemire.me/blog/2026/04/09/a-brief-history-of-c-c-programming-languages/