从1999版开始,ISO C标准定义了一个标准头 <stdint.h>
,其中定义了typedef intmax_t
和 uintmax_t
等 . 这些分别指定"a (signed|unsigned) integer type capable of representing any value of any (signed|unsigned) integer type" .
例如,如果典型地,最宽的有符号和无符号整数类型是 long long int
和 unsigned long long int
,两者通常都是64位,则 intmax_t
和 uintmax_t
可能在_976617中定义,如下所示:
typedef long long int intmax_t;
typedef unsigned long long int uintmax_t;
有一组有限的预定义有符号和无符号整数类型,范围从 signed
, unsigned
和普通 char
到 signed
和 unsigned
long long int
.
C99和C11还允许实现定义扩展的整数类型,这些类型不同于任何标准类型,并且具有实现定义的关键字的名称 .
gcc和clang在某些但不是所有目标上都支持类型 __int128
和 unsigned __int128
. 这些行为类似于128位整数类型,但它们不被视为扩展整数类型,并且两个编译器的文档都声明它们不支持任何扩展整数类型 . 由于这些不是整数类型,因为标准定义了术语,因此typedef intmax_t
和 uintmax_t
适用于64位类型,而不是128位类型 .
这些都不违反C标准(实现不需要任何扩展的整数类型,并且它们违反任何严格符合的程序) . 但在我看来,将 __int128
和 unsigned __int128
视为扩展整数类型, intmax_t
和 uintmax_t
为128位类型是完全合理的 .
不这样做的理由是,更改 intmax_t
和 uintmax_t
的大小将是"an ABI-incompatible change" .
Clang C++ status page在脚注(5)中说:
对于不提供任何扩展整数类型的Clang等实现,不需要进行编译器更改 . __int128不被视为扩展整数类型,因为更改intmax_t将是ABI不兼容的更改 .
(是的,这主要讨论C,但规则与C相同)
在_976638中,声称:
sizeof(intmax_t)由各种LP64 ABI修复,不能更改
在这两种情况下,都没有提到这种说法 .
Headers 为"System V Application Binary Interface, AMD64 Architecture Processor Supplement, Draft Version 0.99.6"的x86_64 ABI document未提及 intmax_t
或 uintmax_t
,甚至 <stdint.h>
Headers . 它确实指定了预定义整数类型的大小和对齐方式(如图3.1所示) .
最后,我的问题是:ABI限制 intmax_t
和 uintmax_t
的大小是否有效?如果是这样,ABI有什么要求? (顺便说一下,为什么?)
(在我看来,这样的要求,如果它存在,是不明智的 . 它违背了C标准允许定义扩展整数类型的目的,以及 intmax_t
和 uintmax_t
的预期含义 . 这使得使用128-更加困难在支持它们的系统上有效地对整数类型进行排序,同时在其他系统上回退到更窄的类型 . )
Update :在 Headers 为"intmax t, a way out"的N2303中,Jens Gustedt建议调整 [u]intmax_t
的定义,以允许添加比_976651更宽的扩展整数类型,而无需更新 [u]intmax_t
. 例如, intmax_t
可能是 long long
的typedef,但实现仍然可以提供 __int128
作为扩展整数类型 .
参考文献:
3 回答
正如上校三十二注释,单方面进行此更改的编译器会破坏传递
uintmax_t
参数或返回uintmax_t
值的编译单元之间的调用 . 尽管SysV ABI没有定义这些类型的传递方式,但实际上保持它们的定义是符合平台ABI的一部分 .即使它没有单方面进行此更改,因为它需要对每个目标平台的C标准库进行匹配更改 . 具体来说,它至少需要更新
printf
和scanf
函数系列,imaxabs
,imaxdiv
,strtoimax
和strtoumax
及其变体 .更改类型如
intmax_t
和uintmax_t
也会更改使用它们的所有程序的ABI,因为它们现在引用不同的类型 .假设您有程序A,它使用共享库B中的函数和
uintmax_t
参数 . 如果GCC改变uintmax_t
的定义并且A(但不是B)被重新编译,那么A中的uintmax_t
和B中的uintmax_t
现在指的是两种不同的类型,打破了ABI .我认为这里要理解的关键是,因为ABI规范中没有记录某些内容并不意味着它不是ABI的一部分 . 只要在库边界上使用类型,它的属性就会成为该库的ABI的一部分 .
通过在标准头中定义(u)intmax_t并在标准库的函数中使用它们成为该库的ABI的一部分,无论它们是否包含在任何正式的ABI规范中 .
对于类似Unix的平台而言,这尤其是一个问题,其中C标准库被视为平台的一部分,而不是编译器的一部分 .
现在可以转换这个 . Printf将宏用于类型说明符,因此可以根据intmax_t的大小对这些宏进行不同的定义 . 宏可以类似地用于将标准库中的少数函数映射到不同的实现,但它是一堆额外的工作以获得可疑的收益,因此gcc采取阻力最小的路径来添加他们需要的功能也就不足为奇了 .