什么ABI(如果有的话)限制[u] intmax_t的大小?

时间:2015-04-28 18:51:16

标签: c c99 c11 abi

从1999版开始,ISO C标准定义了标准标题<stdint.h>,其中定义了typedef intmax_tuintmax_t等。它们分别指定“a(有符号|无符号)整数类型,它能够表示任何(有符号|无符号)整数类型的任何值”。

例如,如果典型的话,最宽的有符号和无符号整数类型是long long intunsigned long long int,两者通常都是64位,那么intmax_t和{{1可能在uintmax_t中定义如下:

<stdint.h>

有一组有限的预定义有符号和无符号整数类型,范围从typedef long long int intmax_t; typedef unsigned long long int uintmax_t; signed和普通unsignedcharsigned unsigned

C99和C11还允许实现定义扩展整数类型,它们不同于任何标准类型,并且具有实现定义关键字的名称。

gcc和clang在某些但不是所有目标上都支持long long int__int128类型。这些操作类似于128位整数类型,但它们视为扩展整数类型,并且两个编译器的文档都声明它们不支持任何扩展整数类型。由于这些不是整数类型,因为标准定义了术语,因此typedef unsigned __int128intmax_t适用于64位类型,而不是128位类型。

这些都不违反C标准(实现不需要任何扩展的整数类型,并且只要它们不破坏任何严格符合的程序,它们就被允许具有任意扩展)。但在我看来,将uintmax_t__int128视为扩展整数类型,unsigned __int128intmax_t为128位类型是完全合理的

这样做的理由是,更改uintmax_tintmax_t的大小将是“ABI不兼容的更改”。

Clang C++ status page在脚注(5)中说:

  

对于没有提供任何扩展整数类型的Clang等实现,不需要进行编译器更改。 uintmax_t不被视为扩展整数类型,因为更改__int128将是ABI不兼容的更改。

(是的,这主要讨论C ++,但规则与C相同。)

gcc bug report中,声明:

  

intmax_t由各种LP64 ABI修复,无法更改

在这两种情况下,均未提及此声明。

标题为“System V应用程序二进制接口,AMD64架构处理器补充,草案版本0.99.6”的x86_64 ABI document未提及sizeof(intmax_t)intmax_t,甚至uintmax_t标头它确实指定了预定义整数类型的大小和对齐方式(如图3.1所示)。

最后,我的问题是:ABI限制的<stdint.h>intmax_t大小是否有效?如果是这样,ABI有什么要求? (顺便说一下,为什么?)

(在我看来,这样的要求,如果它存在,是不明智的。它违背了C标准允许定义扩展整数类型的目的,以及uintmax_tintmax_t的预期含义这使得在支持它们的系统上有效地使用128位整数类型变得更加困难,而在其他系统上又回退到更窄的类型。)

更新:在标题为“intmax t,出路”的N2303中,Jens Gustedt建议调整uintmax_t的定义以允许添加比[u]intmax_t更宽的扩展整数类型无需更新long long。例如,[u]intmax_t可能是intmax_t的typedef,但实现仍然可以提供long long作为扩展整数类型

参考文献:

3 个答案:

答案 0 :(得分:8)

正如上校三十二注释,单方面进行此更改的编译器会破坏通过uintmax_t参数或返回uintmax_t值的编译单元之间的调用。即使SysV ABI没有定义如何传递这些类型,但在实用性方面,维护它们的定义是符合平台ABI的一部分。

即使不是这个ABI问题,编译器仍然无法单方面进行此更改,因为它需要对每个目标平台的C标准库进行匹配更改。具体而言,它至少需要更新printfscanf函数系列imaxabsimaxdiv以及strtoimaxstrtoumax及其变体。

答案 1 :(得分:6)

更改intmax_tuintmax_t等类型也会更改使用它们的所有程序的ABI,因为它们现在引用不同的类型。

假设您有程序A使用共享库B中的函数uintmax_t参数。如果GCC改变了uintmax_t的定义而A(但不是B)被重新编译,那么A中的uintmax_t和B中的uintmax_t现在引用两种不同的类型,打破了ABI。

答案 2 :(得分:1)

我认为这里要理解的关键是,仅因为某项内容未在ABI规范中记录下来,并不意味着它不属于ABI。一旦跨库边界使用了一种类型,该类型的属性就会成为该库的ABI的一部分。

通过在标准标头中定义(u)intmax_t并将其用于标准库的函数中,无论它们是否包含在任何正式的ABI规范中,它们都将成为该库的ABI的一部分。

对于类似Unix的平台,尤其是一个问题,在该平台中C标准库被视为平台的一部分,而不是编译器的一部分。

现在可以进行转换了。 Printf将宏用于类型说明符,因此可以根据intmax_t的大小来不同地定义这些宏。宏可以类似地用于将标准库中的少数功能映射到不同的实现,但是要花很多钱才能获得可疑的收益,因此gcc采取最小的阻力来添加所需功能的途径就不足为奇了。 >