首页 文章

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

提问于
浏览
18

从1999版开始,ISO C标准定义了一个标准头 <stdint.h> ,其中定义了typedef intmax_tuintmax_t 等 . 这些分别指定"a (signed|unsigned) integer type capable of representing any value of any (signed|unsigned) integer type" .

例如,如果典型地,最宽的有符号和无符号整数类型是 long long intunsigned long long int ,两者通常都是64位,则 intmax_tuintmax_t 可能在_976617中定义,如下所示:

typedef long long int intmax_t;
typedef unsigned long long int uintmax_t;

有一组有限的预定义有符号和无符号整数类型,范围从 signedunsigned 和普通 charsignedunsigned long long int .

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

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

这些都不违反C标准(实现不需要任何扩展的整数类型,并且它们违反任何严格符合的程序) . 但在我看来,将 __int128unsigned __int128 视为扩展整数类型, intmax_tuintmax_t 为128位类型是完全合理的 .

不这样做的理由是,更改 intmax_tuintmax_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_tuintmax_t ,甚至 <stdint.h> Headers . 它确实指定了预定义整数类型的大小和对齐方式(如图3.1所示) .

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

(在我看来,这样的要求,如果它存在,是不明智的 . 它违背了C标准允许定义扩展整数类型的目的,以及 intmax_tuintmax_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 回答

  • 8

    正如上校三十二注释,单方面进行此更改的编译器会破坏传递 uintmax_t 参数或返回 uintmax_t 值的编译单元之间的调用 . 尽管SysV ABI没有定义这些类型的传递方式,但实际上保持它们的定义是符合平台ABI的一部分 .

    即使它没有单方面进行此更改,因为它需要对每个目标平台的C标准库进行匹配更改 . 具体来说,它至少需要更新 printfscanf 函数系列, imaxabsimaxdivstrtoimaxstrtoumax 及其变体 .

  • 1

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

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

  • 6

    我认为这里要理解的关键是,因为ABI规范中没有记录某些内容并不意味着它不是ABI的一部分 . 只要在库边界上使用类型,它的属性就会成为该库的ABI的一部分 .

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

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

    现在可以转换这个 . Printf将宏用于类型说明符,因此可以根据intmax_t的大小对这些宏进行不同的定义 . 宏可以类似地用于将标准库中的少数函数映射到不同的实现,但它是一堆额外的工作以获得可疑的收益,因此gcc采取阻力最小的路径来添加他们需要的功能也就不足为奇了 .

相关问题