为啥 C++ 标准库与编译器而不是操作系统捆绑在一起?
Posted
技术标签:
【中文标题】为啥 C++ 标准库与编译器而不是操作系统捆绑在一起?【英文标题】:Why is the C++ standard library bundled with the compiler instead of the os?为什么 C++ 标准库与编译器而不是操作系统捆绑在一起? 【发布时间】:2014-06-17 18:12:00 【问题描述】:如果这是一个幼稚的问题,我很抱歉,但有些事情我无法理解。
为什么 C++ 标准库与不同的编译器实现(g++
的 libstdc++
和 clang
的 libc++
)捆绑在一起,而不是与(类 UNIX)操作系统捆绑在一起,就像,说C标准库呢?考虑到它是 C 库的超集,为什么它不与 C 库一起维护?
【问题讨论】:
@40two 嗯,这是模棱两可的,你是对的。澄清一下,我的意思是为什么它们不在同一个保护伞下维护,例如,在glibc
或另一个 C 标准库项目下。
编译器和库需要就库使用的二进制接口达成一致。 C 编译器(大多数)同意一个通用的调用约定等,因此很容易将库与编译器分开维护。 C++ 编译器在调用约定等方面往往存在差异,因此需要为每个编译器单独编译库。
它没有。被this blog post覆盖。
拥有操作系统并不意味着您需要 C++ 标准库。但几乎可以肯定拥有 C++ 编译器。
@Mysticial:Windows 附带的 libc 库不适用于应用程序。见:blogs.msdn.com/b/oldnewthing/archive/2014/04/11/10516280.aspx
【参考方案1】:
根本原因是没有标准的 C++ ABI —— 每个编译器都倾向于有自己的 ABI,它与其他编译器不同且不兼容。另一方面,大多数操作系统定义了一个标准 C ABI,他们使用并为其提供标准 C 库,并且该操作系统的所有 C 编译器都支持该 ABI。
【讨论】:
+1 用于实际阅读问题并回答它提出的具体问题(为什么 C++ 每个编译器都有一个库,而所有 C 编译器倾向于共享同一个库),而不仅仅是评论切线点(也就是说,从技术上讲,C 库也不是操作系统的一部分)。 实际上,Herb Sutter(来自 Microsoft)正在努力获得一个稳定的 C++ ABI,其模型类似于 C,请参阅n4028: Defining a portable C++ ABI。 @MatthieuM.:不幸的是,该提案的状态实际上只是一组(不完整的)提案要求,没有具体内容。问题是在继承和虚函数定义以及保持向后兼容性方面存在很多陷阱,没有解决它们的好方法 @ChrisDodd:是的,我仍然希望在 C++17 之前还有一段时间 :) 该死,你的回答是在对Firsts Posts
的评论中,我只是想问你是否在谈论 API 而不是 ABI。我失败了,因为我点击了评论……我觉得我被骗了:-)【参考方案2】:
操作系统一般不支持语言。他们只支持自己的系统调用。在大多数操作系统中,这种支持是作为 C 库的一部分提供的,因为 C 具有最低级别的链接。其他语言和运行时(如 C++、python 等)在操作系统的系统调用支持库之上构建它们的运行时支持。
【讨论】:
UNIX 和 C 是由同一群人共同开发的,因此 UNIX 和 POSIX 系统支持 C 并且 C 在许多方面都紧密地融入了操作系统。【参考方案3】:C 库也是分开维护的:glibc 和 Windows 的 msvcr*(不知道 Mac 上的细节)。 “操作系统附带”的事实是所有(大部分)二进制文件都链接到它,所以没有它就什么都不会工作。当然,C++ 标准库也是如此,但没有那么严格。
编译器通常提供库编写者用来促进开发的扩展。当一个新特性被实现时,这个库就会被适配。有时这些变化是破坏性的。对于 glibc/libstdc++(/libc++?),在库内部维护向后兼容性(使用版本化符号)。以 Windows 的 CRT 为例,C 和 C++ 标准库都出现了各种不兼容的版本,并与每个编译器版本相耦合。另外:在 Visual Studio 的情况下,编译器倾向于在版本之间破坏 ABI,因此“操作系统”必须与所有版本的库一起提供。
PS:当然,对于 Windows,在 Windows 更新中包含较新的 CRT/C++lib 版本可能更“干净”。其他选择是在很久以前做出的,而且大部分一直停留到现在。
【讨论】:
不幸的是,一些应用程序访问了 Visual Studio C 运行时的内部,这绝对是应用程序的错,但 Visual Studio 团队不想破坏这些应用程序是可以理解的。【参考方案4】:C++ 库的源代码与 GCC 源代码捆绑在一起。这是有道理的,因为 C++ 库与 C++ 语言齐头并进。它不是操作系统组件。它的某些方面,如内存管理和 I/O,确实与操作系统设施接口,但大部分都没有。
另一方面,C++ 库的实际捆绑是操作系统发行版 的工作(例如某些 GNU/Linux 风格)。
最终,决定如何打包 libstdc++ 的是您的发行版。例如,它可能是一个独立的包(甚至可能需要出现在多个版本中)。这是因为 libstdc++ 提供了一个共享库,并且无论是否安装了编译器,其他包都需要该共享库作为依赖项。有些包可能只适用于这个库的特定版本。
“操作系统的一部分”或“编译器的一部分”实际上没有意义:问题是“什么包的一部分”,这是特定于发行版的,因为当您构建 GCC 套件时,您的构建然后,脚本可以根据您对如何组织发行版的看法将临时安装树分成任意包。
假设我们制作了一个“ceeplusplusy”操作系统发行版。那么 C++ 库可以被认为是操作系统的重要组成部分。也就是说,假设启动操作系统所需的核心应用程序都用 C++ 重写并且都使用库:诸如系统守护程序、shell、“getty”等。然后在早期引导阶段需要 C++ 库。最终,什么是操作系统,什么不是?
【讨论】:
【参考方案5】:在 Mac 上,您可以在 /usr/lib 目录中找到 libc.dylib(标准 C 库)和 libc++.dylib(标准 C++ 库)。在 ios 设备上,您不会(很容易)找到它们,但它们都在那里。很明显,它们不是编译器的一部分,因为它们对于几乎所有程序的运行都是必不可少的,即使您从未安装任何编译器,它们也存在。
【讨论】:
以上是关于为啥 C++ 标准库与编译器而不是操作系统捆绑在一起?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 C++ 编译器不优化对结构数据成员的读写而不是不同的局部变量?
为啥我们需要在 C++ 中使用 `int main` 而不是 `void main`? [复制]