在不同编译器生成的代码之间传递结构
Passing struct between code generated by different compilers
结构的内存布局由编译器决定。那么当一个编译器编译的某些代码使用另一个编译器编译的代码生成的结构时会发生什么?
例如,假设我有一个声明结构 somestruct
的头文件和一个 returns 结构的函数。一个源文件定义了该函数并由编译器 A
编译。另一个源文件使用 than 函数,由编译器 B
和 links 针对另一个源文件的二进制文件编译。
如果两个编译器为somestruct
创建两个不同的布局,那么函数返回的变量的布局是什么?它是否遵循一个编译器的布局,或者当第二个源文件试图访问第一个源文件返回的结构的元素时是否会出现内存错误?是编译时出错还是link时出错?
数据布局(例如结构等...)和调用协议(调用如何在处理器级别完成)在名为 Application Binary Interface 的(特定于处理器和操作系统的)文档中定义.如果两个编译器都遵循相同的 ABI(对于相同的处理器和相同的操作系统),它们生成的代码应该是可互操作的。
参见例如x86 calling conventions and the x86-64 ABI 规范的维基页面。
Name mangling,尤其是对于 C++,也可能是一个问题。
该函数将return一个由函数编译器的ABI指定的结构。被调用者编译器只会将函数视为符合 自身 .
的 ABI
假设两个编译器使用类似的 ABI,在大多数情况下,在编译时或link时甚至在运行时都不会报告错误。对于某些兼容的编译器,如 OS X 和 Linux 上的 Clang、GCC 和 Intel C 编译器,没有错误 should 结果(如果有错误那就是错误编译器)。然而在现实世界中,通常很难找到完全兼容的编译器(在大多数情况下,它们的 ABI 相似 但不完全相同;此类 ABI 错误将更难追踪,因为您的应用在运行时遇到一些非常奇怪的情况下会出现正常和崩溃)。
正如 Basile 所说,C++ 的名称重整在 ABI 中造成了额外的差异,但这种差异在编译时更容易被发现,因为 linker 字面上无法 find函数的符号,而不是找一个不兼容的函数。
此外,在 ABI 方面传递结构是另一个令人头疼的问题,因为存在多个结构打包 ABI,有时在 "compatible" 编译器(如 GCC/MinGW 和 MSVC)中甚至有所不同。 (另请参阅 GCC 中的 -m[no-]ms-bitfields
选项,它强制 GCC 将 MSVC ABI 用于结构。)我还看到一些情况下,通过指针传递结构 more reliable 而不是通过值传递结构。
结构的内存布局由编译器决定。那么当一个编译器编译的某些代码使用另一个编译器编译的代码生成的结构时会发生什么?
例如,假设我有一个声明结构 somestruct
的头文件和一个 returns 结构的函数。一个源文件定义了该函数并由编译器 A
编译。另一个源文件使用 than 函数,由编译器 B
和 links 针对另一个源文件的二进制文件编译。
如果两个编译器为somestruct
创建两个不同的布局,那么函数返回的变量的布局是什么?它是否遵循一个编译器的布局,或者当第二个源文件试图访问第一个源文件返回的结构的元素时是否会出现内存错误?是编译时出错还是link时出错?
数据布局(例如结构等...)和调用协议(调用如何在处理器级别完成)在名为 Application Binary Interface 的(特定于处理器和操作系统的)文档中定义.如果两个编译器都遵循相同的 ABI(对于相同的处理器和相同的操作系统),它们生成的代码应该是可互操作的。
参见例如x86 calling conventions and the x86-64 ABI 规范的维基页面。
Name mangling,尤其是对于 C++,也可能是一个问题。
该函数将return一个由函数编译器的ABI指定的结构。被调用者编译器只会将函数视为符合 自身 .
的 ABI假设两个编译器使用类似的 ABI,在大多数情况下,在编译时或link时甚至在运行时都不会报告错误。对于某些兼容的编译器,如 OS X 和 Linux 上的 Clang、GCC 和 Intel C 编译器,没有错误 should 结果(如果有错误那就是错误编译器)。然而在现实世界中,通常很难找到完全兼容的编译器(在大多数情况下,它们的 ABI 相似 但不完全相同;此类 ABI 错误将更难追踪,因为您的应用在运行时遇到一些非常奇怪的情况下会出现正常和崩溃)。
正如 Basile 所说,C++ 的名称重整在 ABI 中造成了额外的差异,但这种差异在编译时更容易被发现,因为 linker 字面上无法 find函数的符号,而不是找一个不兼容的函数。
此外,在 ABI 方面传递结构是另一个令人头疼的问题,因为存在多个结构打包 ABI,有时在 "compatible" 编译器(如 GCC/MinGW 和 MSVC)中甚至有所不同。 (另请参阅 GCC 中的 -m[no-]ms-bitfields
选项,它强制 GCC 将 MSVC ABI 用于结构。)我还看到一些情况下,通过指针传递结构 more reliable 而不是通过值传递结构。