C++ 二进制代码能否通过本机 C 接口变得可移植?有什么限制?
Can C++ binary code become portable through a native C interface? What are the limitations?
我经常使用该技术将我的高性能 C++ classes 包装成一个薄的 C 层,我编译到共享库,然后用其他编程语言加载它们,例如 Python.
从我在这里和那里的阅读中,我了解到这个工作的唯一要求是让函数接口仅使用本机类型或这些类型的结构。 (因此,int
和 long
s、float
、double
等以及它们的任何级别的指针)。
我的问题是:假设各种编译器之间完全 ABI compatibility,这是我必须满足的唯一要求才能与共享库完全 API 兼容吗?
为什么不能移植C++库?这是我的理解:
情况 1: 考虑类型 std::string
。在内部它包含一个 char*
空终止字符串和一个大小整数。 C++ 标准并没有说明哪一个应该先出现(对吧?)。这意味着如果我把 std::string
放在一个函数接口上,两个不同的编译器可能会有不同的顺序,这是行不通的。
案例 2: 考虑 class 具有虚方法的继承和虚表。 C++ 标准不需要任何特定的 position/order 来指定 vtable 指针的去向(对吗?)。它们可以位于 class 的开头,位于任何其他变量之前,也可以位于末尾,位于所有其他成员变量之后。同样,在函数上连接此 class 将不一致。
我的第一个问题之后的另一个问题:这个问题不是也发生在函数调用中吗?还是编译成二进制后就什么都不重要了,类型就没有意义了? RTTI 元素不会导致问题吗,例如,如果我将它们放在 C 包装器接口中?
没有 C++ ABI 的部分原因是没有 C ABI。正如 Bjarne Stroustrup (source) 所述:
The technical hardest problem is probably the lack of a C++ binary interface (ABI). There is no C ABI either, but on most (all?) Unix platforms there is a dominant compiler and other compilers have had to conform to its calling conventions and structure layout rules - or become unused. In C++ there are more things that can vary - such as the layout of the virtual function table - and no vendor has created a C++ ABI by fiat by eliminating all competitors that did not conform. In the same way as it used to be impossible to link code from two different PC C compilers together, it is generally impossible to link the code from two different Unix C++ compilers together (unless there are compatibility switches).
缺少 ABI 为编译器实现提供了更多自由,并允许将语言传播到多种不同类型的系统。
在 Windows 上有一些依赖于编译器输出结果的方式的平台特定依赖关系,一个例子来自 COM ,其中需要将纯虚拟接口布置在特定的环境中方法。所以 Windows 大多数编译器至少会同意这一点。
Windows API 使用 stdcall
调用约定,因此在针对 Windows API 进行编码时,有一套固定的规则如何将参数传递给函数。但这同样取决于系统,并且没有什么可以阻止您编写使用不同约定的程序。
我经常使用该技术将我的高性能 C++ classes 包装成一个薄的 C 层,我编译到共享库,然后用其他编程语言加载它们,例如 Python.
从我在这里和那里的阅读中,我了解到这个工作的唯一要求是让函数接口仅使用本机类型或这些类型的结构。 (因此,int
和 long
s、float
、double
等以及它们的任何级别的指针)。
我的问题是:假设各种编译器之间完全 ABI compatibility,这是我必须满足的唯一要求才能与共享库完全 API 兼容吗?
为什么不能移植C++库?这是我的理解:
情况 1: 考虑类型 std::string
。在内部它包含一个 char*
空终止字符串和一个大小整数。 C++ 标准并没有说明哪一个应该先出现(对吧?)。这意味着如果我把 std::string
放在一个函数接口上,两个不同的编译器可能会有不同的顺序,这是行不通的。
案例 2: 考虑 class 具有虚方法的继承和虚表。 C++ 标准不需要任何特定的 position/order 来指定 vtable 指针的去向(对吗?)。它们可以位于 class 的开头,位于任何其他变量之前,也可以位于末尾,位于所有其他成员变量之后。同样,在函数上连接此 class 将不一致。
我的第一个问题之后的另一个问题:这个问题不是也发生在函数调用中吗?还是编译成二进制后就什么都不重要了,类型就没有意义了? RTTI 元素不会导致问题吗,例如,如果我将它们放在 C 包装器接口中?
没有 C++ ABI 的部分原因是没有 C ABI。正如 Bjarne Stroustrup (source) 所述:
The technical hardest problem is probably the lack of a C++ binary interface (ABI). There is no C ABI either, but on most (all?) Unix platforms there is a dominant compiler and other compilers have had to conform to its calling conventions and structure layout rules - or become unused. In C++ there are more things that can vary - such as the layout of the virtual function table - and no vendor has created a C++ ABI by fiat by eliminating all competitors that did not conform. In the same way as it used to be impossible to link code from two different PC C compilers together, it is generally impossible to link the code from two different Unix C++ compilers together (unless there are compatibility switches).
缺少 ABI 为编译器实现提供了更多自由,并允许将语言传播到多种不同类型的系统。
在 Windows 上有一些依赖于编译器输出结果的方式的平台特定依赖关系,一个例子来自 COM ,其中需要将纯虚拟接口布置在特定的环境中方法。所以 Windows 大多数编译器至少会同意这一点。
Windows API 使用 stdcall
调用约定,因此在针对 Windows API 进行编码时,有一套固定的规则如何将参数传递给函数。但这同样取决于系统,并且没有什么可以阻止您编写使用不同约定的程序。