标准Linux库函数strtoull
的上限为64位。
是否存在strtoX
的实现 - Linux x86_64环境的系列函数是否在uint128_t
整数上运行?
可能的原型:
uint128_t strtoulll(const char *nptr, char **endptr, int base);
另外,如何使用uint128_t
/ printf
打印sprintf
整数?
答案 0 :(得分:2)
标准中没有类型uint128_t
。类型__int128
仅在J.5.6中被称为“公共扩展名”,但仍不是官方标准的一部分(列出的类型显然已签名,而非未签名)。
请注意strtoull
&家庭是标准的一部分,而不是Linux(无论“Linux”在何处)。
所以:没有标准的转换方式,也没有printf。
答案 1 :(得分:1)
据我所知,C11标准中没有uint128_t
类型
GCC有内置类型__uint128_t
,但printf
和strtoull
(标准函数)都不支持此类型。
您可以为C找一些 bigint 库。
我编写了一个strtoulll
函数,除了扩展的返回类型外,其行为应该与标准strtoull
相似。我还编写了一个非常非常非常简单的 sprint_uint128t
函数,它将128位无符号数的十进制表示形式打印到颠倒顺序的字符串中。这只是因为我不想实现整个printf
类克隆。将字符串反转将有助于尾随零/空格和其他格式化的东西
只提供十进制版本,因为hex / bin可以使用标准格式化说明符和八进制来轻松模拟...来自八进制128位数字?
使用此代码需要您自担风险。另外,我喜欢糟糕的C代码
#include <stdio.h>
#include <inttypes.h>
#include <ctype.h>
#include <errno.h>
__uint128_t strtoulll(const char *nptr, char **endptr, int base)
{
int cbase = base ? base : 10;
__uint128_t result = 0, tmp;
int negate = 0, c, error=EINVAL;
if (base < 0 || base > 36)
goto error;
while (isspace(*nptr++));
nptr--;
if (*nptr == '-' || *nptr == '+')
{
negate = *nptr^'+';
nptr++;
}
if (*nptr == '0' && base == 0)
{
cbase = 8;
nptr++;
if (*nptr == 'x')
{
cbase = 16;
nptr++;
}
}
while (nptr)
{
c = *nptr-0x30;
c = c < 10 ? c : c-7;
c = c < 36 ? c : c-0x20;
if (c < 0 || c >= cbase)
goto error_setptr;
error = 0;
tmp = result*cbase + c;
if ((tmp-c)/cbase != result)
{
error = ERANGE;
goto error;
}
result = tmp;
nptr++;
}
result = negate ? -result : result;
error_setptr:
if (endptr)
*endptr = (char*)nptr;
error:
errno = error;
return result;
}
void sprint_uint128(__uint128_t v, char* str)
{
int c;
do
{
c = v % 10;
v = v / 10;
*str++ = c+'0';
}
while (v);
*str = 0;
}
int main()
{
__uint128_t t;
unsigned long long l, h;
int e;
char* p;
char buf[100];
t = strtoulll(" 340282366920938463463374607431768211455", &p, 0);
e = errno;
l = t & 0xffffffffffffffffULL;
h = t >> 64;
printf("Hex value %llx%016llx\nerr %d\nfirst unrecog char %d(%c)\nERANGE=%d, EINVAL=%d\n",
l, h, e, *p, *p, ERANGE, EINVAL);
sprint_uint128(t, buf);
printf("\n\nPrinted dec reversed %s\n", buf);
return 0;
}
当然这只适用于GCC。
注意想知道在C中进行更好的128位溢出检查吗?
答案 2 :(得分:1)
在重新思考我的问题后,我得出了这个答案。
gcc info:gcc version 4.9.1(Ubuntu 4.9.1-16ubuntu6)
目标:x86_64-linux-gnu
编译:gcc -o /不带标记
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <ctype.h>
#include <errno.h>
typedef __uint128_t uint128_t;
typedef __uint64_t uint64_t;
typedef __uint8_t uint8_t;
const char *hex = "ffffffffffffffff0000000000000000";
uint8_t ascii2hex( char s )
{
uint8_t r = 0xf;
if( (s >= 48) && (s <= 57) )
r = s - 48;
else if( (s >= 65) && ( s <= 70) )
r = s - 55;
else if( (s >= 97) && (s <= 102) )
r = s - 87;
return r;
}
uint128_t hex_strtoulll(const char *nptr, int len)
{
int i;
uint128_t r = 0, p;
for(i = len; i >= 0; i--)
{
p = (uint128_t)ascii2hex(*(nptr + i));
p = p << ((len - i) << 2);
r |= p;
}
return r;
}
int printf_uint128_t(uint128_t x)
{
return printf("%016"PRIx64"%016"PRIx64"\n",(uint64_t)(x>>64),(uint64_t)x);
}
int main(int argc, char **argv)
{
uint128_t x = hex_strtoulll(hex, strlen(hex) - 1);
uint128_t a = 0xffffffffffffffff;
uint128_t b = 0xf;
uint128_t c = a * b;
printf_uint128_t(x);
printf_uint128_t(c);
printf_uint128_t(x - (c));
return 0;
}
我唯一想到的问题是为什么我不能直接加载uint128_t值? 出现此消息:警告:整数常量对于其类型而言太大。 在uint128_t值为2 ^ 64 - 1的情况下,警告消息为true。
uint128_t x = 0xfffffffffffffffffffffffffffffff;
sizeof(uint128_t) == 16
虽然这可以按预期工作:
uint128_t x = -1;