可以安全地假设在任何实际可用的平台ABI中定义了哪些项目?
的价值 CHAR_BIT
尺寸,对齐要求和对象表示:
void*,size_t,ptrdiff_tunsigned char 和 signed charintptr_t 和 uintptr_tfloat,double和long doubleshort 和 long longint和long(但在这里,我希望"不")空对象指针的对象表示
空函数指针的对象表示
例如,如果我有一个库(由未知但符合ABI的编译器编译)发布此函数:
void* foo(void *bar, size_t baz, void* (*qux)());
Run Code Online (Sandbox Code Playgroud)
我可以假设能够在我的程序中安全地调用它,无论我使用哪个编译器?
或者,反过来说,如果我正在编写一个库,是否有一组类型,如果我将库的公共接口限制为此集,它将保证在它构建的所有平台上都可用?
C 标准在附录中包含了整个部分,总结如下:
J.3 实现定义的行为
完全随机的子集:
一个字节中的位数
signed char和哪个unsigned char相同char
多字节和宽字符串的文本编码
有符号整数表示
将指针转换为整数的结果,反之亦然 (6.3.2.3)。请注意,这意味着任何指针,而不仅仅是对象指针。
更新:为了解决您有关 ABI 的问题:ABI(应用程序二进制接口)不是一个标准化概念,并且没有任何地方说实现必须指定 ABI。ABI 的组成部分部分是语言的实现定义的行为(尽管不是全部;例如,有符号到无符号的转换是实现定义的,但不是 ABI 的一部分),并且大多数实现定义的方面语言由硬件决定(例如有符号整数表示、浮点表示、指针大小)。
然而,ABI 更重要的方面是函数调用如何工作,即参数存储在哪里、谁负责清理内存等。两个编译器就这些约定达成一致至关重要,以便它们的代码能够二进制兼容。
在实践中,ABI 通常是实施的结果。一旦编译器完成,它就会根据其实现来确定 ABI。它可能会记录此 ABI,其他编译器以及同一编译器的未来版本可能会遵守这些约定。对于 x86 上的 C 实现,这种方法工作得相当好,并且只有少数(通常有详细记录的)自由参数需要进行通信才能实现代码的互操作。但对于其他语言,尤其是 C++,您会看到完全不同的情况:根本没有任何东西可以接近 C++ 的标准 ABI。Microsoft 的编译器在每个版本中都会破坏 C++ ABI。GCC 努力维护跨版本的 ABI 兼容性,并使用已发布的 Itanium ABI(讽刺的是,对于现在已死的架构)。其他编译器可能会做自己的、完全不同的事情。(然后您当然会遇到 C++ 标准库实现的问题,例如您是否string包含一个、两个或三个指针,以及按什么顺序?)
总结一下:编译器 ABI 的许多方面,尤其是与 C 相关的方面,都是由硬件体系结构决定的。只要函数调用约定等某些方面能够正确传达,同一硬件的不同 C 编译器就应该生成兼容的二进制代码。然而,对于高级语言来说,一切都是不可能的,两个不同的编译器是否可以生成可互操作的代码必须根据具体情况来决定。