结构的内存布局取决于编译器。那么当一个编译器编译的代码使用由另一个编译器编译的代码生成的结构时会发生什么呢?
例如,假设我有一个声明结构somestruct
的头文件,以及一个返回结构的函数。一个源文件定义该函数,由编译器A
编译。另一个源文件使用而不是函数,由编译器B
编译,并链接到另一个源文件的二进制文件。
如果两个编译器为somestruct
创建两个不同的布局,那么该函数返回的变量的布局是什么?它是否遵循一个编译器的布局,或者当第二个源文件试图访问第一个源文件返回的结构元素时会出现内存错误?在编译时或链接时是错误吗?
答案 0 :(得分:3)
数据的布局(例如结构等......)和调用协议(如何在处理器级别完成调用)在称为Application Binary Interface的(处理器和操作系统特定的)文档中定义。如果两个编译器都遵循相同的ABI(对于相同的处理器和相同的操作系统),则它们生成的代码应该是可互操作的。
参见例如x86 calling conventions和x86-64 ABI规范的wikipage。
Name mangling,特别是对于C ++,也可能是一个问题。
答案 1 :(得分:3)
该函数将返回函数编译器的ABI指定的结构。被调用者编译器只会将该函数视为符合本身的ABI 。
假设两个编译器使用类似的 ABI,在大多数情况下,在编译时或链接时甚至在运行时期间都不会报告错误。对于某些兼容的编译器,如OS X和Linux上的Clang,GCC和Intel C Compiler,应该结果没有错误(如果有错误那么它就是编译器的错误)。然而在现实世界中,通常很难找到完全兼容的编译器(在大多数情况下,他们的ABI 相似但不完全相同;这样的ABI错误将更难追踪,因为您的应用程序看似正常在运行时遇到一些非常奇怪的情况下崩溃。
就像Basile所说的那样,C ++的名称错误在ABI中带来了额外的差异,但是这些差异在编译期间更容易被捕获,因为链接器实际上不能找到函数的符号,而不是找到一个不兼容的功能。
此外,传递结构是ABI方面的另一个难题,因为有多种结构包装ABI,有时甚至在“兼容”编译器(如GCC / MinGW和MSVC)中也不同。 (另请参阅GCC中的-m[no-]ms-bitfields
选项,它强制GCC将MSVC ABI用于结构。)我还看到一些情况,其中通过指针传递结构more reliable比按值传递结构。