128 位整数类型仅在 64 位目标上可用,因此即使您已经检测到最近的 GCC 版本,您也需要检查可用性。理论上 gcc 可以在需要 4 个 32 位寄存器来保存一个的机器上支持 TImode 整数,但我认为在任何情况下都不会。
GCC 4.6 及更高版本将__int128 / unsigned __int128 定义为内置类型。 使用
#ifdef __SIZEOF_INT128__ 来检测它。
GCC 4.1 及更高版本将__int128_t 和__uint128_t 定义为内置类型。 (这些也不需要#include <stdint.h>。证明on Godbolt。)
我测试了on the Godbolt compiler explorer 的第一个版本的编译器来支持这三样东西(在 x86-64 上)。 Godbolt 只回溯到 gcc4.1、ICC13 和 clang3.0,所以我使用
legacy recommended(?) | One way of detecting support
__uint128_t | [unsigned] __int128 | #ifdef __SIZEOF_INT128__
gcc <= 4.1 | 4.6 | 4.6
clang <= 3.0 | 3.1 | 3.3
ICC <= 13 | <= 13 | 16. (Godbolt doesn't have 14 or 15)
如果您为 ARM 等 32 位架构或带有 -m32 的 x86 进行编译,即使是这些编译器的最新版本也不支持 128 位整数类型。 需要在使用之前检测支持,如果您的代码在没有它的情况下可以正常工作。
我知道用于检测它的唯一直接 CPP 宏是 __SIZEOF_INT128__,但不幸的是,一些旧的编译器版本支持它而没有定义它。 (并且__uint128_t 没有宏,只有 gcc4.6 样式 unsigned __int128)。 How to know if __uint128_t is defined
有些人仍然在 RHEL (RedHat Enterprise Linux) 或类似的老旧系统上使用 gcc4.4 等古老的编译器版本。如果你关心过时的 gcc 版本,你可能想坚持__uint128_t。并且可能根据sizeof(void*) == 8 检测64 位作为__SIZEOF_INT128__ 未定义的后备。 (我认为 GNU 系统总是有CHAR_BIT==8)。这将对 64 位 ISA(如 x86-64 Linux x32 或 AArch64 ILP32)上的 ILP32 ABI 产生误报,但这对于使用未定义 __SIZEOF_INT128__ 的旧编译器的人来说已经只是一个后备/奖励。
可能有一些 64 位 ISA,其中 gcc 没有定义 __int128,或者甚至可能有一些 32 位 ISA,其中 gcc 确实 定义了 __int128,但我不知道任何一个。
正如此处另一个答案中的 cmets 所指出的,GCC 内部是整数 TI 模式。 (四整数 = int 的 4 倍宽度,DImode = 双宽度 vs. SImode = 普通 int。)与 the GCC manual points out 一样,__int128 在支持 128 位整数模式的目标上受支持(TImode )。
// __uint128_t is pre-defined equivalently to this
typedef unsigned uint128 __attribute__ ((mode (TI)));
随机事实:ICC19 和 g++/clang++ -E -dM 定义:
#define __GLIBCXX_TYPE_INT_N_0 __int128
#define __GLIBCXX_BITSIZE_INT_N_0 128
@MarcGlisse 评论 这就是你告诉 libstdc++ 处理额外整数类型(重载 abs、专门化类型特征等)的方式
icpc 定义了即使使用-xc(编译为 C,而不是 C++),而 g++ -xc 和 clang++ -xc 没有。但是使用实际的 icc 进行编译(例如,在 Godbolt 下拉菜单中选择 C 而不是 C++)并没有定义这个宏。
测试函数是:
#include <stdint.h> // for uint64_t
#define uint128_t __uint128_t
//#define uint128_t unsigned __int128
uint128_t mul64(uint64_t a, uint64_t b) {
return (uint128_t)a * b;
}
支持它的编译器都可以有效地编译它,以
mov rax, rdi
mul rsi
ret # return in RDX:RAX which mul uses implicitly