在uint128_t整数的上下文中对十六进制字符串的操作

时间:2015-06-27 13:01:32

标签: c linux x86-64

标准Linux库函数strtoull的上限为64位。

是否存在strtoX的实现 - Linux x86_64环境的系列函数是否在uint128_t整数上运行?

可能的原型:

uint128_t strtoulll(const char *nptr, char **endptr, int base);

另外,如何使用uint128_t / printf打印sprintf整数?

3 个答案:

答案 0 :(得分:2)

标准中没有类型uint128_t。类型__int128仅在J.5.6中被称为“公共扩展名”,但仍不是官方标准的一部分(列出的类型显然已签名,而非未签名)。

请注意strtoull&家庭是标准的一部分,而不是Linux(无论“Linux”在何处)。

所以:没有标准的转换方式,也没有printf。

答案 1 :(得分:1)

据我所知,C11标准中没有uint128_t类型 GCC有内置类型__uint128_t,但printfstrtoull(标准函数)都不支持此类型。

您可以为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;