Intereting Posts
Что получает () эквивалент в C11? Может ли fseek (stdin, 1, SEEK_SET) или перемотка назад (stdin) использоваться для сброса входного буфера вместо не-портативного fflush (stdin)? (K & R) По крайней мере, первые 31 символа внутреннего имени значительны? Операторы сравнения для строк C Как сделать дочерний процесс с теми же переменными среды, что и parrent plus, который является собственным в Windows? передача аргументов между c и встроенной сборкой Stange поведение с моей обратной связью строки C Как написать короткий блок встроенной расширенной сборки gnu для замены значений двух целых переменных? Как найти простое число без использования моей функции chk prime, так как я хочу оптимизировать свой алгоритм Чтение из файла с помощью функции read () Почему следующие значения дают мне ошибку преобразования от double *** до const double *** Интерпретация выхода STRACE – труб и вилок алгоритм в O (n) сложности времени, чтобы найти пару nos в массиве, которые имеют самое близкое различие между собой Типы данных Windows … почему так избыточно / undescriptive? не удалось подключиться к библиотеке fftw3

Операции с шестнадцатеричными строками в контексте целых чисел uint128_t

Верхний предел для стандартной библиотечной функции Linux strtoull – 64 бит.

Существует ли реализация функции strtoX -family для среды x86_64 для Linux, которая работает с uint128_t числами uint128_t ?

Возможный прототип:

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

Кроме того, как вы можете напечатать uint128_t числа uint128_t используя printf / sprintf ?

Нет стандарта uint128_t по стандарту. Тип __int128 упоминается как «общее расширение» только в J.5.6 , но по-прежнему не является частью официального стандарта (и указанный тип явно подписан, а не без знака).

Обратите внимание, что strtoull & family являются частью стандарта, а не Linux (что означает «Linux» здесь).

Итак: нет стандартного способа конвертировать, ни в printf.

Насколько я знаю, в стандарте C11 нет типа uint128_t.
GCC имеет встроенный тип __uint128_t , однако printf и strtoull (являющиеся стандартными функциями) предлагают поддержку для этого типа.

Вы можете найти некоторую библиотеку bigint для C.

Я написал функцию strtoulll которая должна вести себя как стандартная strtoull за исключением расширенного типа возврата. Я также написал очень очень простую функцию sprint_uint128t которая печатает десятичное представление 128-битного беззнакового числа в строку в обратном порядке. Это происходит только потому, что я не хотел реализовывать целый printf как клон. Однако, если перестроить цепочку, это поможет с завершающими нулями / пробелами и другими форматированием.
Предоставляется только десятичная версия, поскольку hex / bin можно легко эмулировать с помощью стандартного спецификатора форматирования и восьмеричного … пришли на восьмеричные 128-битные номера?

Используйте этот код на свой страх и риск. Кроме того, мне нравится плохой стиль кода C

ЭТО ОЧЕНЬ ПЛОХОЙ СТИЛЬНЫЙ КОД. НАЧИНАЮТСЯ НЕ ДОПУСКАЮТ, ЧТОБЫ ПОПАДАТЬ ЭТО, НО КРЫШЕ НАПИШИТЕ ЭТО ОТ ОТКРЫТИЯ

 #include  #include  #include  #include  __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.

Примечание. Любая идея для лучшей проверки переполнения 128 бит в C?

После переосмысления моего вопроса я вышел с этим ответом.

gcc info: gcc version 4.9.1 (Ubuntu 4.9.1-16ubuntu6)

objective: x86_64-linux-gnu

Скомпилирован с помощью: gcc -o / without flags

 #include  #include  #include  #include  #include  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? Появится это сообщение: warning: integer constant слишком велика для своего типа. Предупреждающее сообщение истинно выше значения uint128_t 2 ^ 64 – 1.

  uint128_t x = 0xfffffffffffffffffffffffffffffff; sizeof(uint128_t) == 16 

тогда как это работает так, как ожидалось:

  uint128_t x = -1;