C 编译器参考实现

C compiler reference implementation

有多种语言具有其 compiler/libraries 的参考实现,但为什么 C 没有参考实现?
我知道 GCC 和 glibc 被广泛使用并且 Microsoft 有他们也使用的版本,但为什么不是一个主要实现,例如 python?(是的,我知道还有其他实现,但有一个 MAIN/Reference python)
它是否与 OS 类似 linux 和 Windows 在 C 中实现至少一部分 API 这一事实有关?谢谢。

我想这更像是一个历史问题,而不是技术问题。简短的回答是:有一个,有点。它没有采取。长答案相当长,具体取决于您想要了解多少细节。

C老了。我的意思是,python 也很旧,但是 C 真的 很旧。 Dennis Ritchie 于​​ 1960 年代末在贝尔实验室一起破解了它的第一个版本,他这样做是为了不必用汇编或 B(这是一种现在已经被遗忘的当时的系统编程语言)编写 UNIX C 的一些缺点是为了解决)。

这可以说是与今天的语言设计完全不同的方法:C 是为了编写 UNIX 而编写的。没有人为了设计一种漂亮干净的系统编程语言而坐下来设计 C。这些家伙想编写一个操作系统并构建一个工具,让他们更容易地做到这一点。

但是,这个贝尔实验室的 C 编译器是一种参考实现,因为 C 本质上是 C 团队编写到他们的编译器中的内容。然后是便携式 C 编译器,它应该使将 C 移植到新平台更容易,还有名为 "The C Programming Language" 的书(又名非正式的 K&R C 规范),C 开始流行,一切都很好。然后事情就变得复杂了。

C 在它仍然流行的时候就开始流行了……让我们宽容地说 "some room for improvement." 当然有;每种语言总是有改进的余地。对于初学者来说,没有真正的标准库。编译时不检查函数参数,函数不能 return voidstruct 之类的东西。边缘仍然粗糙。

但现在不仅仅是贝尔实验室,哦不。现在有几十家供应商,他们都对 pcc 或自己开发的编译器进行了改编,并且有很多关于改进 C 的方式的好主意,有时也不是那么好。与设计一种语言相比,他们对设计一种工具更感兴趣,这些工具可以使他们的 实际 工作更简单。所以他们编写了自己的语言扩展,有时这些扩展与其他人提出的扩展并不相符。

现在,很容易面对面质问他们为什么不更好地协调语言开发,但实际上并没有那么简单。当时互联网还不存在,所以他们不能只是建立一个 IRC 频道来讨论东西,而且......好吧,与今天相比,编程语言并不是唯一混乱的东西。

如今,大多数计算机都非常相似。我们都将负整数表示为二进制补码,字节几乎总是 8 位宽,指针只是内存地址。当时情况并非如此,当你考虑到当 C 被标准化时,周围仍然有机器使用一个补码或有符号数,你就会明白为什么 C 中没有定义有符号溢出。你有没有见过旧 DOS 程序的 C 代码?他们有近指针和远指针的概念,因为旧的 16 位 x86 计算机需要特殊的分段寄存器来寻址超过 64KB 的 RAM。几个编译器为此构建了 C 扩展,但相信我,您非常非常高兴今天的 C 不包含这个概念。苏联人建造了一台平衡的三元计算机,尽管我不确定它是否支持 C。简而言之,硬件环境也很混乱,这对于接近金属的语言来说是一件大事。

所以,每个人都做了他们必须做的事,而且通常(尽管并不总是)尽其所能,但语言必然存在分歧。一个语言核心最终在 1989 年被标准化(当安德泰克……等一下,错误的年份)以恢复一些表面上的秩序,几年后编译器开始收敛于它。尽管如此,一些旧的扩展永远不会消失,因为向后兼容性始终是一个问题——想想 python 3 被采用的速度有多快——还有一些接近金属的问题需要解决使语言有用但不能明智地写入规范,因为它们不可移植,例如调用约定。

好了。 C 具有语言规范而不是参考实现的原因主要是历史原因,部分原因是它必须在不同的机器上 运行.

我想开发一个官方参考实现是可能的(至少对于一些通用平台),但我也相信它的价值会有些有限。毕竟,C 标准必须留下许多未定义的东西,因为它无法知道底层机器的确切性质,因此只要您输入的代码格式正确,所有其他实现的行为只会像参考实现一样.对于格式良好的代码,通常的 C 实现(即 gcc、clang、MSVC)通常以相同的方式运行,因此您可以使用其中任何一个。