GCC 4.7.1 手册说:
6.8 128 位整数
作为扩展,整数标量类型__int128
支持具有足够宽以容纳 128 位的整数模式的目标。只需写__int128
一个有符号的 128 位整数,或
unsigned __int128
一个无符号的 128 位整数。GCC 不支持为具有小于 [ sic ] 128 位宽度的整数__int128
的目标表示类型的整数常量。long long
有趣的是,尽管没有提及__uint128_t
,但即使设置了严格的警告,也可以接受该类型:
#include <stdio.h>
int main(void)
{
__uint128_t u128 = 12345678900987654321;
printf("%llx\n", (unsigned long long)(u128 & 0xFFFFFFFFFFFFFFFF));
return(0);
}
汇编:
$ gcc -O3 -g -std=c99 -Wall -Wextra -pedantic xxx.c -o xxx
xxx.c: In function ‘main’:
xxx.c:6:24: warning: integer constant is so large that it is unsigned [enabled by default]
$
(这是在 Mac OS X 10.7.4 上使用家庭编译的 GCC 4.7.1。)
将常量更改为0x12345678900987654321
,编译器会说:
xxx.c: In function ‘main’:
xxx.c:6:24: warning: integer constant is too large for its type [enabled by default]
所以,操纵这些生物并不容易。十进制常量和十六进制常量的输出是:
ab54a98cdc6770b1
5678900987654321
对于十进制打印,最好的办法是查看该值是否大于 UINT64_MAX;如果是,则除以小于 UINT64_MAX 的 10 的最大幂,打印该数字(并且您可能需要第二次重复该过程),然后以小于 10 的最大幂为模打印残差UINT64_MAX,记得用前导零填充。
这导致类似:
#include <stdio.h>
#include <inttypes.h>
/*
** Using documented GCC type unsigned __int128 instead of undocumented
** obsolescent typedef name __uint128_t. Works with GCC 4.7.1 but not
** GCC 4.1.2 (but __uint128_t works with GCC 4.1.2) on Mac OS X 10.7.4.
*/
typedef unsigned __int128 uint128_t;
/* UINT64_MAX 18446744073709551615ULL */
#define P10_UINT64 10000000000000000000ULL /* 19 zeroes */
#define E10_UINT64 19
#define STRINGIZER(x) # x
#define TO_STRING(x) STRINGIZER(x)
static int print_u128_u(uint128_t u128)
{
int rc;
if (u128 > UINT64_MAX)
{
uint128_t leading = u128 / P10_UINT64;
uint64_t trailing = u128 % P10_UINT64;
rc = print_u128_u(leading);
rc += printf("%." TO_STRING(E10_UINT64) PRIu64, trailing);
}
else
{
uint64_t u64 = u128;
rc = printf("%" PRIu64, u64);
}
return rc;
}
int main(void)
{
uint128_t u128a = ((uint128_t)UINT64_MAX + 1) * 0x1234567890ABCDEFULL +
0xFEDCBA9876543210ULL;
uint128_t u128b = ((uint128_t)UINT64_MAX + 1) * 0xF234567890ABCDEFULL +
0x1EDCBA987654320FULL;
int ndigits = print_u128_u(u128a);
printf("\n%d digits\n", ndigits);
ndigits = print_u128_u(u128b);
printf("\n%d digits\n", ndigits);
return(0);
}
输出是:
24197857200151252746022455506638221840
38 digits
321944928255972408260334335944939549199
39 digits
我们可以使用以下方法进行验证bc
:
$ bc
bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
ibase = 16
1234567890ABCDEFFEDCBA9876543210
24197857200151252746022455506638221840
F234567890ABCDEF1EDCBA987654320F
321944928255972408260334335944939549199
quit
$
显然,对于十六进制,过程更简单;您只需两个操作即可移动、遮罩和打印。对于八进制,由于 64 不是 3 的倍数,因此您必须通过类似的步骤进行十进制运算。
print_u128_u()
界面并不理想,但它至少会返回打印的字符数,就像现在一样printf()
。调整代码以将结果格式化为字符串缓冲区在编程中并非完全是微不足道的练习,但也不是非常困难。