用不同的 C++ 编译器构建的二进制文件和库如何兼容?

How can binary files and libraries built with different C++ compilers be compatible?

编译器在他们生成的代码中有很大的自由度。他们在实现 VTable、RTTI、异常等方面拥有完全的自由。即使是非常基本的东西,如指针的大小、调用函数的方式和名称修改也可以任意选择,独立于操作系统和体系结构。

然而,我在使用任何编译器(Clang、GCC、ICC、MSVC)、任何操作系统(Android、Linux、Mac OS、Windows),在任何架构(x86、x86-64、ARM)上并将其链接到使用不同编译器构建的库。

所有二进制文件如何与其他二进制文件兼容?

二进制文件是否被运行时链接程序或类似程序动态“改编”?

编译器是否就某些标准达成一致?如果是这样,我在哪里可以找到有关这些二进制级实际标准的信息?

很多时候它们是不兼容的。以下是一些可能发现的不兼容性:

不同的数据类型大小

例如,GCC 使用 16 个字节作为 long double,而 VS 将其别名为 double(8 个字节)。有关详细信息,请查看 this.

如果两个尺寸都已知,这可以很容易地解决,因为尺寸之间的转换是微不足道的(但可能会导致精度损失)。

名称修改

这可能是最广为人知的问题。 C++ 编译器需要修饰符号,以便(在许多事情中)函数重载成为可能。没有标准的名称修改方案,因此编译器选择了自己的名称修改方案,这会导致不兼容,因为例如,使用 VS 编译的代码可能无法识别使用 GCC 编译的库中的名称,甚至无法识别早期版本的 VS。

这可以通过不修饰名称并将它们导出为未修饰的 C 函数来解决。然而,这意味着 class 方法必须包装在 C 函数中才能导出它们(因为 C 不理解 classes),这并不是很方便。

Visual C++ name mangling scheme

GCC name mangling scheme