从1999版开始,ISO C标准定义了一个标准头<stdint.h>,其中定义了typedef intmax_t和uintmax_t.它们分别指定"能够表示任何(有符号|无符号)整数类型的任何值的(有符号|无符号)整数类型".
例如,如果像典型的是,最宽的符号和无符号整数类型是long long int和unsigned long long int,这两者通常是64位,则intmax_t和uintmax_t在可能被定义<stdint.h>如下:
typedef long long int intmax_t;
typedef unsigned long long int uintmax_t;
Run Code Online (Sandbox Code Playgroud)
有一组预定义的有限符号和无符号整数类型,从的signed,unsigned和普通char高达signed和unsigned long long int.
C99和C11还允许实现定义扩展的整数类型,这些类型不同于任何标准类型,并且具有实现定义的关键字的名称.
gcc和clang在某些但不是所有目标上都支持类型__int128和unsigned __int128.这些行为类似于128位整数类型,但它们不被视为扩展整数类型,并且两个编译器的文档都声明它们不支持任何扩展整数类型.因为这些都不是整数类型的标准定义的术语,该类型定义intmax_t和uintmax_t是64位类型的,而不是128位的类型.
这些都不违反C标准(实现不需要具有任何扩展的整数类型,并且只要它们不破坏任何严格符合的程序,它们就被允许具有任意扩展).但在我看来,它将使完美感__int128和unsigned __int128被视为扩展整数类型,以及intmax_t和uintmax_t为128位的类型.
不这样做的理由是改变大小intmax_t并且uintmax_t将是"ABI不兼容的变化".
该锵C++状态页说,在脚注(5):
对于没有提供任何扩展整数类型的Clang等实现,不需要进行编译器更改.
__int128不被视为扩展整数类型,因为更改intmax_t将是ABI不兼容的更改.
(是的,这主要讨论C++,但规则与C相同)
在gcc错误报告中,声称:
sizeof(intmax_t)由各种LP64 ABI修复,不能更改
在这两种情况下,都没有提到这种说法.
一个x86_64的ABI文件名为"System V应用程序二进制接口,AMD64架构处理器补充,草案版本0.99.6"并没有提及intmax_t或者uintmax_t,甚至<stdint.h>头.它确实指定了预定义整数类型的大小和对齐方式(如图3.1所示).
最后,我的问题是:声称ABI 的大小intmax_t和uintmax_t限制是否有效?如果是这样,ABI有什么要求?(顺便说一下,为什么?)
(在我看来,这样的规定,如果存在的话,是不明智的.它击败了C标准的定义扩展整型许可的目的,和的用意intmax_t和uintmax_t,这使得它更难于使用128位整数在支持它们的系统上有效地进行类型化,同时在其他系统上回退到更窄的类型.)
更新:在标题为"intmax t,一个出路"的N2303中,Jens Gustedt建议调整[u]intmax_t允许添加扩展整数类型的定义,long long而不必更新[u]intmax_t.例如,intmax_t可能是一个typedef long long,但实现仍然可以提供,比方说,__int128作为一个扩展整型.
参考文献:
正如上校三十二注释,单方面进行此更改的编译器会破坏传递uintmax_t参数或返回uintmax_t值的编译单元之间的调用.尽管SysV ABI没有定义这些类型的传递方式,但实际上保持其定义是符合平台ABI的一部分.
即使不是因为这个ABI问题,编译器仍然无法单方面进行此更改,因为它需要对每个目标平台的C标准库进行匹配更改.具体地讲,它至少需要更新的printf和scanf函数族,imaxabs,imaxdiv,和strtoimax和strtoumax及其变体.
更改类型intmax_t并且uintmax_t还会更改使用它们的所有程序的ABI,因为它们现在引用不同的类型.
假设您有程序A,它使用共享库B中的函数和uintmax_t参数.如果GCC改变了定义uintmax_t并且A(但不是B)被重新编译,那么uintmax_t在A和uintmax_tB中现在引用两种不同的类型,打破ABI.
我认为这里要理解的关键是,某些内容没有记录在 ABI 规范中并不意味着它不是 ABI 的一部分。一旦跨库边界使用类型,它的属性就会成为该库的 ABI 的一部分。
通过在标准头中定义 (u)intmax_t 并在标准库的函数中使用它们,无论它们是否包含在任何正式的 ABI 规范中,它们都会成为该库的 ABI 的一部分。
对于类 Unix 平台来说,这尤其是一个问题,其中 C 标准库被视为平台的一部分,而不是编译器的一部分。
现在可以转变这一点。Printf 使用宏作为类型说明符,因此这些宏可以根据 intmax_t 的大小进行不同的定义。宏可以类似地用于将标准库中的少数函数映射到不同的实现,但这需要大量额外的工作来获得可疑的收益,因此 gcc 采取阻力最小的路径来添加所需的功能也就不足为奇了。