As far as I know there is no uint128_t
type in the C11 stardard.
GCC has a built in type __uint128_t
, however nor printf
nor strtoull
(being standard functions) offer support for this type.
You may look for some bigint library for C.
I have wrote a strtoulll
function that should behave like to standard strtoull
except for the widened return type. I have also write a very very very simple sprint_uint128t
function that print the decimal representation of a 128 bit unsigned number to a string in the reversed order. This is just because I didn't feel like implementing a whole printf
like clone. Having the string reversed will help with trailing zeros/spaces and other formatting things however.
Only the decimal version is provided as hex/bin can be emulated easy with standard formatting specifier and octal... came on octal 128 bit numbers?
Use this code at your own risk. Also, I like bad styled C code
THIS IS VERY BAD STYLED CODE. BEGINNERS SHOULD NOT COPY PASTE IT BUT RATHER WRITE IT ENTIRELY FROM SCRATCH
#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;
}
Of course this is for GCC only.
Note Any idea for a better 128 bit overflow checking in C?