从1999版开始,ISO C标准定义了标准标题<stdint.h>
,其中定义了typedef intmax_t
和uintmax_t
等。它们分别指定“a(有符号|无符号)整数类型,它能够表示任何(有符号|无符号)整数类型的任何值”。
例如,如果典型的话,最宽的有符号和无符号整数类型是long long int
和unsigned 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
和普通unsigned
到char
和signed
unsigned
。
C99和C11还允许实现定义扩展整数类型,它们不同于任何标准类型,并且具有实现定义关键字的名称。
gcc和clang在某些但不是所有目标上都支持long long int
和__int128
类型。这些操作类似于128位整数类型,但它们不视为扩展整数类型,并且两个编译器的文档都声明它们不支持任何扩展整数类型。由于这些不是整数类型,因为标准定义了术语,因此typedef unsigned __int128
和intmax_t
适用于64位类型,而不是128位类型。
这些都不违反C标准(实现不需要任何扩展的整数类型,并且只要它们不破坏任何严格符合的程序,它们就被允许具有任意扩展)。但在我看来,将uintmax_t
和__int128
视为扩展整数类型,unsigned __int128
和intmax_t
为128位类型是完全合理的
不这样做的理由是,更改uintmax_t
和intmax_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_t
和intmax_t
的预期含义这使得在支持它们的系统上有效地使用128位整数类型变得更加困难,而在其他系统上又回退到更窄的类型。)
更新:在标题为“intmax t,出路”的N2303中,Jens Gustedt建议调整uintmax_t
的定义以允许添加比[u]intmax_t
更宽的扩展整数类型无需更新long long
。例如,[u]intmax_t
可能是intmax_t
的typedef,但实现仍然可以提供long long
作为扩展整数类型。
参考文献:
答案 0 :(得分:8)
正如上校三十二注释,单方面进行此更改的编译器会破坏通过uintmax_t
参数或返回uintmax_t
值的编译单元之间的调用。即使SysV ABI没有定义如何传递这些类型,但在实用性方面,维护它们的定义是符合平台ABI的一部分。
即使不是这个ABI问题,编译器仍然无法单方面进行此更改,因为它需要对每个目标平台的C标准库进行匹配更改。具体而言,它至少需要更新printf
和scanf
函数系列imaxabs
,imaxdiv
以及strtoimax
和strtoumax
及其变体。
答案 1 :(得分:6)
更改intmax_t
和uintmax_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采取最小的阻力来添加所需功能的途径就不足为奇了。 >