第20.2章:C 独立实现与 C++ 独立实现

English

1. C 在 1989 年就把独立实现做成了可用的东西

C 在标准化几乎其他任何东西之前就标准化了独立实现,因为这门语言的用户当时就在写内核,而一份描述不了 Unix 的标准是没有用的。要求是四个头文件:

<float.h>   <limits.h>   <stdarg.h>   <stddef.h>

这就是一个符合标准的 C 独立实现必须拥有的全部库,而且从 1989 年至今没有变过。仔细看这份清单,因为它不是按口味选的子集:每一项都是一个编译器必须知道其内容的头文件。NULL 与 size_t、每种整数类型的取值范围、double 的表示,以及可变参数列表如何遍历。没有一项能用普通源码写出来,所以也没有一项能在不使语言不可实现的前提下被删除。其余的一切 —— printf、malloc、FILE —— 都是宿主的,独立 C 程序就是没有它们,而所有人都觉得这可以接受,因为内核本来也不会去调 printf。

还要注意 C 独立实现没有强加给你什么:这门语言没有异常、没有 RTTI、没有 new、没有线程库、没有隐藏的分配。"独立实现必须提供的库"和"独立实现能够实现的库"之间没有任何差距,因为那份清单是从编译器自身的需要里划出来的,没有别的东西。

2. C++ 把独立实现变成了一个承诺而不是一份清单

C++03 确实有一节讲独立实现。它要求 C 的头文件,加上语言自身特性所需要的 <new>、<typeinfo> 和 <exception> 中的一部分 —— 而错误就在这里。这些头文件之所以存在,是因为 C++ 有 new、RTTI 和异常,而这些特性需要一个运行时:一个堆、类型信息对象、一个 unwinder。于是 C++ 独立实现要求了需要运行时的头文件,而独立目标没有那个运行时。标准描述了一个它实现不了的库。

后面的一切都是由此推出的。一个符合标准的独立 C++ 实现,得为一块只有 8 KiB 内存的板子提供 `__cxa_allocate_exception` 和一个 personality routine。没有厂商这么干,所以每一个真实的独立 C++ 构建早已是"不符合标准"的,而标准自己的文字描述了一门没人编译的语言。

CC++
Freestanding specified since 自何时起规定了独立实现 1989 年,此后从未改变
1998 年,且如所写无法实现 Four, all compiler-owned 必需的头文件
四个,全由编译器掌管 很多,其中好几个需要目标没有的运行时 Exceptions, RTTI, new, and their support library
语言强加给你的特性 除算术和函数调用之外没有 异常、RTTI、new,以及它们的支撑库
Gap between the standard and reality 内核要合规得怎么做 照常编译

把这些特性关掉,然后变得不符合标准

3. The Paper That Named the Problem

标准与现实之间的差距

没有

"用 -fno-exceptions -fno-rtti -nostdlib,然后祈祷"

这就是为什么遗留异常那一章不是口味问题。在独立目标上,选项从来不是"异常还是错误码",而是"异常还是一份符合标准的构建"。

3. 给这个问题命名的论文

P1105R0《Leaving no room for a lower-level language: A C++ Subset》 在引言里说出了内核和嵌入式领域的每个人二十年前就知道的事: