67

我想要一个 128 位整数,因为我想存储两个 64 位数字相乘的结果。gcc 4.4 及更高版本中有这样的东西吗?

4

3 回答 3

41

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>这些。Godbolt 上的证明。)

在 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)

如果您针对 ARM 或 x86 等 32 位架构进行编译,-m32则即使这些编译器的最新版本也不支持 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)。这将对 64 位 ISA(如 x86-64 Linux x32 或 AArch64 ILP32)上的 ILP32 ABI 产生误报,但这对于使用未定义__SIZEOF_INT128__.

可能有一些 64 位 ISA,其中 gcc 没有定义__int128,甚至可能有一些 32 位 ISA,其中 gcc确实定义__int128了,但我不知道。


正如对此处另一个答案的评论所指出的那样,GCC 内部是整数 TI 模式。(四整数 = 的 4 倍宽度int,与 DImode = 双倍宽度与 SImode = plain int。)正如GCC 手册所指出的__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即使使用(编译为 C,而不是 C++)也定义了这一点-xc,而 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
于 2019-02-21T19:43:27.083 回答
33

啊,大整数不是 C 的强项。

GCC 确实有一个unsigned __int128/__int128类型,从版本 4.something 开始(这里不确定)。但是,我似乎确实记得__int128_t在那之前有一个定义。

这些仅在 64 位目标上可用。

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

于 2013-04-18T16:31:29.550 回答
17

您可以使用处理任意或大精度值的库,例如GNU MP Bignum Library

于 2013-04-18T16:28:08.897 回答