在 gcc 中有一个128位整数吗?

我想要一个128位整数,因为我想要存储两个64位数字乘法的结果。GCC 4.4及以上有这样的东西吗?

101439 次浏览

您可以使用处理任意或大精度值的库,例如 比格纳姆图书馆

大整数不是 C 的强项。

GCC 确实有一个 unsigned __int128/__int128类型,从版本4开始。某事(这里不确定)。然而,我似乎确实记得,在那之前有一个 __int128_t Def。

这些只能在64位目标上使用。

(编者按: 这个答案曾经声称 gcc 定义了 uint128_tint128_t。我在 Godbolt 编译器资源管理器上测试的版本中,没有一个在定义这些类型时没有前导 __,即从 gcc4.1到8.2,或者 clang 或 ICC。)

对于 C23之前的 GCC,基本的128位整数类型是 只能在64位目标上使用,因此即使已经检测到最近的 GCC 版本,也需要检查可用性。理论上,gcc 可以在机器上支持 TImode 整数,这需要4x 32位寄存器来保存一个,但是我不认为在任何情况下它可以做到这一点。

在 C + + 中,考虑一个类似于 boost::multiprecision::int128_t的库,如果可用的话,它希望使用编译器内置的宽类型,与使用自己的 typedef (如 GCC 的 __int128或 Clang 的 _BitInt(128))相比,开销为零。另见 @ phuclv 的回答关于另一个问题。

ISO C23将允许您使用 typedef unsigned _BitInt(128) u128 ,模仿 叮当声的特征,最初称为 _ExtInt(),甚至可以在32位机器上工作; 请参阅 一个简短的介绍。当前的 GCC -std=gnu2x甚至还不支持这种语法。


GCC 4.6及更高版本的 __int128/unsigned __int128定义为内置类型
#ifdef __SIZEOF_INT128__ 来检测它。

GCC 4.1及更高版本将 __int128_t__uint128_t定义为内置类型 。(这些也不需要 #include <stdint.h>。证明 在戈德博尔特身上)

我测试了 在 Godbolt 编译器浏览器上的第一个编译器版本,以支持以上3种情况(在 x86-64上)。Godbolt 只能回到 gcc4.1、 ICC13和 clang3.0,所以我使用 < = 4.1来表明实际的第一个支持可能更早。

         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)

如果您编译的是32位的架构,比如 ARM,或者使用 -m32编译 x86,那么即使是这些编译器的最新版本也不支持128位整数类型。所以你 需要在使用之前检测是否支持,如果你的代码可以在没有它的情况下工作的话。

我所知道的用于检测它的唯一直接 CPP 宏是 __SIZEOF_INT128__,但不幸的是,一些旧的编译器版本不定义它就支持它。(对于 __uint128_t没有宏,只有 gcc4.6样式的 unsigned __int128)。如何知道 _ _ uint128 _ t 是否已定义

有些人仍然使用古老的编译器版本,比如 RHEL (RedHat Enterprise Linux)上的 gcc4.4,或者类似的老式系统。如果您关心这样的过时的 gcc 版本,那么您可能希望坚持使用 __uint128_t。并且可能检测64位的 sizeof(void*) == 8作为 __SIZEOF_INT128__没有被定义的后备。(我认为 GNU 系统总是有 CHAR_BIT==8,尽管我可能对一些 DSP 有误解)。这会给64位 ISA (比如 x86-64 Linux x32,或者 AArch64 ILP32)上的 ILP32 ABI 一个错误的否定,但是对于使用没有定义 __SIZEOF_INT128__的旧编译器的人来说,这已经是一个备用/额外的好处。

可能有一些64位的 ISA,gcc 没有定义 __int128,或者甚至有一些32位的 ISA,gcc 是的定义 __int128,但是我不知道有这样的情况。


GCC 内部是整数 TI 模式(海湾合作委员会内部手册)。(四整数 = 32位 int的4倍宽度,相对于 DImode = 双倍宽度,相对于 SImode = 普通 int。)作为 海湾合作委员会手册指出,在支持128位整数模式(TImode)的目标上支持 __int128

// __uint128_t is pre-defined equivalently to this
typedef unsigned uint128 __attribute__ ((mode (TI)));

手册中有一个 OImode,oct-int = 32字节,但是当前 x86-64的 GCC 抱怨“无法模拟‘ OI’”,如果您尝试使用它。


随机事实: ICC19和 g + +/clang + + -E -dM定义:

#define __GLIBCXX_TYPE_INT_N_0 __int128
#define __GLIBCXX_BITSIZE_INT_N_0 128

@ MarcGlisse 评论 这就是告诉 libstdc + + 处理额外整数类型(重载 abs、专门化类型 trait 等)的方法

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