gcc中有128位整数吗?

Posted

技术标签:

【中文标题】gcc中有128位整数吗?【英文标题】:Is there a 128 bit integer in gcc? 【发布时间】:2013-04-11 21:10:46 【问题描述】:

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

【问题讨论】:

看一看:***.com/questions/3329541/… @chux:你为什么重新打开这个?这里的最佳答案是错误的,声称uint128_t 是在实际上gcc 提供unsigned __int128__uint128_t 时定义的。目前仅适用于 64 位目标,其中 128 位仅需要 2 个整数寄存器。 @PeterCordes I VTO 作为列出的 2 个受骗者没有回答问题。我的 VTO 与任何答案无关。 @chux: 好吧,这很公平,但它不是作为Does gcc support 128-bit int on amd64? 的副本而关闭的吗?对我来说,这看起来像是重复的。 @PeterCordes 这个问题由于 2 个骗子而被关闭:question 更窄,所以不是这个问题的骗子——还有另一个。 answer 一般在 4.6 及之前解决 gcc,但不是这个问题是关于 4.4 以后的。当然,这些和许多其他相关问题是相似的,并且处于足够相似/不同的边界 【参考方案1】:

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

【讨论】:

Reed 对非 64 位机器给出了完全有效的答案。这个问题是对“C int128”搜索的第一反应,因此对任何平台都有一个通用的答案是一件好事。也许下次如果您对这个主题感到如此强烈,请写一个答案而不是撕毁别人(这样您也可以获得代表收益)。 @CrazyCasta 拥有一个仅用于 128 位类型的任意精度库太浪费了,而且开销也太大了。像Boost.Multiprecision or calccrypto/uint128_t 这样的固定宽度库会更小更快【参考方案2】:

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

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

这些仅适用于 64 位目标。

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

【讨论】:

long long int 在我使用的每个实现中都是 64 位,包括 x86-64 的 GCC。而且我相信 GCC 的 128 位 int 只能在 64 位平台上使用。 我刚刚在 2 个系统中尝试过,它们支持您的结果。我已经删除了它长达 128 位的断言。 Linux x86_64 上的 gcc 4.7.2 没有 []int128_t。我想 gcc 4.8.0 可能有它。 试试typedef int really_long __attribute__ ((mode (TI)));。它已经工作了很长时间(在原生 64 位架构上)。 gcc-4.1 -m64 及以上版本支持__uint128_t out-of-the-box,还支持以下typedef:typedef unsigned uint128_t __attribute__ ((mode (TI)));【参考方案3】:

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

【讨论】:

unsigned __int128 - 全除法是最糟糕的。通常(尤其是 div / mod 算术例程)我们知道商将适合 64 位结果,但 C 运行时不能假设它。我使用__int128 编写了一个参考“modexp”(64 位基数、指数、模数)……与使用 64 位内在函数的版本、reciprocal division 等相比,18x i> 加速! 3x 或 4x 是可观的,但请记住,总有调用开销,并且 [u]int128 函数无法做出我们可以做出的算法断言! @BrettHale:很有趣。 gcc 的辅助函数可能只检查上半部分是否为零,而不是(对于无符号)检查 divisor &gt; high_half_dividend 快速类型并不是了解架构位数的好方法。例如,musl 在 x86_64 上的 ,uint_fast16,32_ts 是 32 位的,glibc 是 64 位(也不好包含在 API 中)。 @PSkocik:不知道为什么我什至首先建议这样做。我想我一直希望找到甚至可以在 ILP32 ABI 上工作的东西,比如 x86-64 Linux 的 x32 或 AArch64 ILP32,但事实并非如此。很高兴听到 MUSL 在 x86-64 上使其成为 32 位;这对我来说更有意义。我没有意识到它没有被 ABI 确定,因此不适合在 API 中使用。 @PSkocik:64 位整数在用作数组索引时有时可以保存符号扩展指令,但在其他方面则更糟。较大的代码大小(REX 前缀),在 Intel CPU (~2.5x) 上更慢 div。在 Zen 之前的 AMD 上,64 位 mul/imul 比 32 位慢。此外,64 位 popcnt 在某些 CPU 上速度较慢。 (所有这些都与 32 位相比,它是 x86-64 机器代码中的默认操作数大小,它免费零扩展为 64 位。)

以上是关于gcc中有128位整数吗?的主要内容,如果未能解决你的问题,请参考以下文章

GCC 中有固定大小的整数吗?

使用 gmp 固定大小的整数...?

Cortex-A57 可以双发 128 位 neon 指令吗?

内联汇编代码和存储 128 位结果

如何将一个 XMM 128 位寄存器拆分为两个 64 位整数寄存器?

SSE 将整数加载到 __m128