22

我可以使用 c++11 中的任何东西并期望编译的二进制文件可以在旧系统上运行吗?我如何知道 c++11 的哪些部分是 libstdc++.so 的一部分,以及实际编译到二进制文件中的是什么?也许我不完全理解这些事情是如何运作的。c++11 是否会破坏旧库的 ABI 合规性?

一个清晰的例子:

假设我编译了一个使用 auto 和基于新范围的 for 循环的程序。这些东西似乎应该在具有旧 c++ 运行时的系统上工作,因为它们分解为在这些机器上有效的 c++。但是,使用正则表达式之类的东西应该会在旧系统上中断,因为它不会在它们的运行时中。

我还没有测试我的理论,因为我无法访问与 c++11 兼容的编译器,而且我的谷歌搜索也没有帮助。

4

2 回答 2

13

你是对的。代码本身可以编译以在任何带有 C++ 编译器的平台上工作。新的语言结构(范围for、新关键字auto等)使用新编译器进行编译,以便在旧系统上正常工作。

但是,如果您尝试将使用新符号(如正则表达式)的代码链接到旧库,那么无论您是静态链接还是动态链接,都会遇到问题,因为旧库没有新符号。

假设您的代码使用新符号:

  • 如果静态链接到旧库,则链接将失败,因为旧库中不存在新符号。
  • 如果您动态链接到旧库,您仍然应该遇到链接器问题,因为该库不包含新符号。
  • 如果您静态链接到新库,则生成的二进制文件将在旧系统上运行。
  • 如果您动态链接到新库,则生成的二进制文件将在旧系统上运行,前提是它已经有新库,或者如果您将新库与二进制文件一起分发。
    • 但是,如果您随后尝试用旧动态库替换新动态库,它将无法链接到该库中的新符号,因为它们不存在。
于 2013-11-01T20:02:57.100 回答
3

该标准不对任何与早期实现一起使用的东西做出任何保证。规范定义了对实现的要求,而一个实现要么符合这些要求,要么不符合这些要求。将 C++11 实现的部分与早期实现的部分拼接在一起是不可移植的,而且实际上不太可能。

即使编写一个根本不使用标准库且不使用任何 C++11 功能的程序也可能与 C++03 实现的二进制文件不兼容。例如,实现者可能会利用新版本来更改调用约定。因此,通常将程序限制为auto和 range-for 之类的功能不一定与 ABI 兼容。

我如何知道 c++11 的哪些部分是 libstdc++.so 的一部分,以及实际编译到二进制文件中的是什么?

即使您不使用标准库的任何部分(您可以通过简单地不使用任何头文件来保证这一点),这也不能保证编译后的二进制文件不需要 C++11 实现提供的运行时支持。一些可能依赖于运行时支持的语言特性示例是异常和虚拟成员。

同样,运行时库支持并不是 C++03 和 C++11 之间唯一可能导致 ABI 不兼容的东西。

c++11 是否会破坏旧库的 ABI 合规性?

不,我认为规范不需要任何阻止 C++03 和 C++11 实现共享 ABI 的东西。但是,您想知道的是,旧规范是否足够严格,以至于旧实现必须具有可能由 C++11 实现共享的 ABI?答案也没有,因此实现者在实现 C++11 时可能被迫破坏 ABI 兼容性。


特定的 C++03 和 C++11 实现可能会共同保证将 C++11 编译的二进制文件与 C++03 运行时支持混合在一起,因此您可以利用它。但是,我不知道有任何这样的实现。

另一种选择是,与其尝试混合 C++11 和 C++03 实现,您的 C++11 实现可能能够创建自包含的二进制文件(或者大部分是自包含的,因为至少它必须依赖不需要外部运行时支持的操作系统的系统调用 ABI)。

您可以依赖的兼容性是源代码级别。您可以编写也编译为 C++03 的 C++11 程序,以及也编译为 C++11 的 C++03 程序,当然,使用这种方法,您仅限于 C++ 之间的最低公分母03 和 C++11 以及您可以从中受益的唯一 C++11 特性是移动语义。

于 2014-02-12T18:29:38.367 回答