我在查看不同的C实现时听说过,任何希望实现C的系统都必须最低限度地包含某些库,stdarg.h等。我的问题是为什么会这样,它不可能是如果没有一些标题,C库就没有图灵完整,而且由于标题已经写好,我必须自己编写它们。那么,为什么不允许C实现只包含编译器+链接器工具链? (当然,在这种情况下,与OS的交互需要内联汇编或链接的汇编代码以及系统的系统调用等知识,但这并不意味着C不能写的,是吗?)
答案 0 :(得分:2)
您混淆了编程语言的属性,即语言本身与标准规定的其他功能。
关于所需的图书馆:您的前提是错误的。 C很好地允许省略库本身。这是托管(完整库)和独立(少数特定于目标的标头,但没有生成代码)之间的区别。请参阅4p6。
少数标头通常是编译器本身的一部分。它们基本上提供了一些typedef
和#define
d常数,例如整数类型的范围(limits.h
)和保证最小宽度的类型(stdint.h
,通常也是固定宽度类型)。 stddef.h
例如{}提供size_t
和NULL
。
虽然您不需要使用这些标头,但它们已经允许为程序逻辑编写可移植代码。只需将它们视为语言本身的一部分,为目标量身定制。
例如,gcc C编译器实际上是一个独立的实现:它只提供所需的头,但不提供标准库。相反,它依赖于系统库,例如, Linux上的glibc。
注意:通常重新发明轮子是个坏主意。因此,如果您使用的是托管环境(即完全成熟的操作系统),则应使用可用的功能。否则你可能会遇到麻烦,例如mightr提供代码不直接看到的其他功能。例如。调试或系统/用户范围的配置,如本地化支持。调试支持也可能取决于您使用标准库,例如Valgrind的。用你自己的代码替换内存分配至少会使这更加困难。
更不用说可维护性了。如果您使用标准名称和语义,并且您自己 - 不仅仅是其他人会更容易理解您的代码 - 只需等待几年并尝试理解您的旧代码。
OTOH,如果你使用的是裸机嵌入式系统,实际上很少使用标准库的大部分功能。包括例如printf
或scnaf
只会使您的固件膨胀,通常没有任何实际用途。对于这样的系统,存在简化的库(例如newlib
),其可能不完全符合或允许省略某些昂贵的特征,例如,浮点转换或数学库。如果你真的需要它们的许多功能,你仍然应该使用它们。有时候有一种中间方式,但这需要一些关于库的依赖性的知识。
答案 1 :(得分:0)
两个原因:兼容性和系统交互。
如果你没有实现整个C标准库,那么其他人写的代码就不会起作用。即使是最基本的C程序也使用库调用。
#include <stdio.h>
int main() {
printf("Hello world!\n");
return 0;
}
如果没有商定且完全实现的stdio.h
程序将无法运行,因为编译器不知道printf()
的含义。
然后是系统互动。 C被称为&#34;便携式组装&#34;。这是因为不同的计算环境以不同的方式做事情,但C对你来说就是这样(好吧,其中一些)。您无法在程序集中编写便携式stdio.h
而不会失去理智。但它不止于此。每个C头文件都可以保护您免受每个环境(或以前)执行的操作的影响。
stdlib.h
使您免受不同的内存模型和过程控制。stdio.h
可以保护您免受不同IO系统的侵害。math.h
使您免受不同浮点实现的影响。limits.h
可以保护您免受不同数据大小的影响。locale.h
可以保护您免受不同语言环境的影响。C库提供了每个环境都可以写入的标准API。当C被移植到新环境时,该环境负责根据该系统的细节实现这些库。 您 不必这样做。
现在我们生活在一个比开发C更加同质的环境中,但是大多数C标准库仍然可以保护您免受操作系统和硬件操作方式的基本差异的影响。
它并不总是这样。想到的一个例子是在DOS上运行游戏的地狱。声卡和视频卡没有标准接口(如果有的话)。 每个程序都必须为他们支持的每个声卡和视频卡发送驱动程序。如果你不在那里,抱歉。如果他们的司机有错误,抱歉。
没有C标准库的编程就像那样,但更糟糕的是。