我想要一个128位整数,因为我想要存储两个64位数字乘法的结果。GCC 4.4及以上有这样的东西吗?
您可以使用处理任意或大精度值的库,例如 比格纳姆图书馆。
大整数不是 C 的强项。
GCC 确实有一个 unsigned __int128/__int128类型,从版本4开始。某事(这里不确定)。然而,我似乎确实记得,在那之前有一个 __int128_t Def。
unsigned __int128
__int128
__int128_t
这些只能在64位目标上使用。
(编者按: 这个答案曾经声称 gcc 定义了 uint128_t和 int128_t。我在 Godbolt 编译器资源管理器上测试的版本中,没有一个在定义这些类型时没有前导 __,即从 gcc4.1到8.2,或者 clang 或 ICC。)
uint128_t
int128_t
__
对于 C23之前的 GCC,基本的128位整数类型是 只能在64位目标上使用,因此即使已经检测到最近的 GCC 版本,也需要检查可用性。理论上,gcc 可以在机器上支持 TImode 整数,这需要4x 32位寄存器来保存一个,但是我不认为在任何情况下它可以做到这一点。
在 C + + 中,考虑一个类似于 boost::multiprecision::int128_t的库,如果可用的话,它希望使用编译器内置的宽类型,与使用自己的 typedef (如 GCC 的 __int128或 Clang 的 _BitInt(128))相比,开销为零。另见 @ phuclv 的回答关于另一个问题。
boost::multiprecision::int128_t
_BitInt(128)
ISO C23将允许您使用 typedef unsigned _BitInt(128) u128 ,模仿 叮当声的特征,最初称为 _ExtInt(),甚至可以在32位机器上工作; 请参阅 一个简短的介绍。当前的 GCC -std=gnu2x甚至还不支持这种语法。
typedef unsigned _BitInt(128) u128
_ExtInt()
-std=gnu2x
GCC 4.6及更高版本的 __int128/unsigned __int128定义为内置类型 #ifdef __SIZEOF_INT128__ 来检测它。
#ifdef __SIZEOF_INT128__
GCC 4.1及更高版本将 __int128_t和 __uint128_t定义为内置类型 。(这些也不需要 #include <stdint.h>。证明 在戈德博尔特身上)
__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位整数类型。所以你 需要在使用之前检测是否支持,如果你的代码可以在没有它的情况下工作的话。
-m32
我所知道的用于检测它的唯一直接 CPP 宏是 __SIZEOF_INT128__,但不幸的是,一些旧的编译器版本不定义它就支持它。(对于 __uint128_t没有宏,只有 gcc4.6样式的 unsigned __int128)。如何知道 _ _ uint128 _ t 是否已定义
__SIZEOF_INT128__
有些人仍然使用古老的编译器版本,比如 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__的旧编译器的人来说,这已经是一个备用/额外的好处。
sizeof(void*) == 8
CHAR_BIT==8
可能有一些64位的 ISA,gcc 没有定义 __int128,或者甚至有一些32位的 ISA,gcc 是的定义 __int128,但是我不知道有这样的情况。
GCC 内部是整数 TI 模式(海湾合作委员会内部手册)。(四整数 = 32位 int的4倍宽度,相对于 DImode = 双倍宽度,相对于 SImode = 普通 int。)作为 海湾合作委员会手册指出,在支持128位整数模式(TImode)的目标上支持 __int128。
int
// __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定义:
-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 + +)并不能定义这个宏。
icpc
-xc
icc
测试功能是:
#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