Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning 128 bit integer in C

Tags:

c

gcc

When I try to assign an 128 bit integer in gcc 4.9.1, I get a warning: integer constant is too large for its type.

Example Code

int main(void) {   __uint128_t p = 47942806932686753431;    return 0; } 

Output

I'm compiling with gcc -std=c11 -o test test.c and I get:

test.c: In function ‘main’: test.c:2:19: warning: integer constant is too large for its type    __uint128_t p = 47942806932686753431;                ^ 

Am I doing something wrong or is this a bug in gcc?

like image 870
iblue Avatar asked Jul 16 '15 17:07

iblue


People also ask

How do you write a 128-bit integer?

DrinkMoreBoilingWater's blog. As an extension the integer scalar type __int128 is supported for targets which have an integer mode wide enough to hold 128 bits. Simply write __int128 for a signed 128-bit integer, or unsigned __int128 for an unsigned 128-bit integer.

How do I store a 128-bit number?

If you only need to store it then you can store it in a byte array like "char num128[16]". If you need to manipulate it you need to use big numbers library like GMP. Show activity on this post. It is not possible to store it in one primitive data type, so we have to be slightly more creative.

Is there a 128-bit integer?

Software. In the same way that compilers emulate e.g. 64-bit integer arithmetic on architectures with register sizes less than 64 bits, some compilers also support 128-bit integer arithmetic. For example, the GCC C compiler 4.6 and later has a 128-bit integer type __int128 for some architectures.

What is the 128-bit integer limit?

The 128-bit data type can handle up to 31 significant digits (compared to 17 handled by the 64-bit long double). However, while this data type can store numbers with more precision than the 64-bit data type, it does not store numbers of greater magnitude.


2 Answers

Am I doing something wrong or is this a bug in gcc?

The problem is in 47942806932686753431 part, not in __uint128_t p. According to gcc docs there's no way to declare 128 bit constant:

There is no support in GCC for expressing an integer constant of type __int128 for targets with long long integer less than 128 bits wide.

So, it seems that while you can have 128 bit variables, you cannot have 128 bit constants, unless your long long is 128 bit wide.

The workaround could be to construct 128 bit value from "narrower" integral constants using basic arithmetic operations, and hope for compiler to perform constant folding.

like image 84
el.pescado - нет войне Avatar answered Sep 20 '22 00:09

el.pescado - нет войне


Have you tried this?

__int128 p = *(__int128*) "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"; 

EDIT Nov. 25

Sorry for the poor clarification on previous post. Seriously, I didn't post this answer as a joke. Though the GCC doc states there's no way to express a 128-bit integer constant, this post simply provides a workaround for those who wants to assign values to __uint128_t variables with ease.

You may try to comile the code below with GCC (7.2.0) or Clang (5.0.0). It prints desired results.

#include <stdint.h> #include <stdio.h>  int main() {     __uint128_t p = *(__int128*) "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";     printf("HIGH %016llx\n", (uint64_t) (p >> 64));     printf("LOW  %016llx\n", (uint64_t) p);     return 0; } 

The stdout:

HIGH 0f0e0d0c0b0a0908 LOW  0706050403020100 

This is only regarded as a workaround since it plays tricks on pointers by placing the "value" in .rodata section (if you objdump it), and it's not portable (x86_64 and aarch64 are fine but not arm and x86). I think it's been enough for those coding on desktop machines.

like image 20
jerry73204 Avatar answered Sep 19 '22 00:09

jerry73204