Assigning 128 bit integer in C

c++ 128-bit integer
print 128 bit integer c
128 bit integer c#
c 128 bit unsigned integer
gcc print 128-bit integer
msvc 128-bit integer
c++ 128-bit integer class
print 128-bit integer c

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?

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.

60846 – Add 128-bit integer types for general use on 32-bit/64-bit , Assignee: Not yet assigned to anyone Since 32-bit and 64-bit CPUs typically cannot operate on 128-bit Note with __builtin_*_overflow, implementing 128bit integer (or larger) as a class for C++ should be easier now. An integer type that determines how a bit-field's value is interpreted. The type may be int, signed int, or unsigned int. 2: member_name. The name of the bit-field. 3: width. The number of bits in the bit-field. The width must be less than or equal to the bit width of the specified type.

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.

128-bit unsigned integer, This implements 128-bit unsigned integer using C++14. It works on MSVC and 32-bit architectures being complementary to the unsigned __� 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.

I had same issue and cooked up a solution using user-defined literals. Here is how you instantiate the user-defined literal _xxl:

int main(int argc, char** argv) {

    auto a = 0xF0000000000000000000000000000000LLU;
    auto b = 0xF0000000000000000000000000000000_xxl;

    printf("sizeof(a): %zu\n", sizeof(a));
    printf("sizeof(b): %zu\n", sizeof(b));

    printf("a == 0? %s\n", a==0 ? "true":"false");
    printf("b == 0? %s\n", b==0 ? "true":"false");

    printf("b >> 124 = %x\n", b >> 124);

    return 0;
}

Output:

sizeof(a): 8
sizeof(b): 16
a == 0? true
b == 0? false
b >> 124 = f

Here is the implementation for the user-defined literal _xxl

#pragma once

#include <stdint.h>

#ifdef __SIZEOF_INT128__
    using uint_xxl_t = __uint128_t;
    using sint_xxl_t = __int128_t;

namespace detail_xxl
{
    constexpr uint8_t hexval(char c) 
    { return c>='a' ? (10+c-'a') : c>='A' ? (10+c-'A') : c-'0'; }

    template <int BASE, uint_xxl_t V>
    constexpr uint_xxl_t lit_eval() { return V; }

    template <int BASE, uint_xxl_t V, char C, char... Cs>
    constexpr uint_xxl_t lit_eval() {
        static_assert( BASE!=16 || sizeof...(Cs) <=  32-1, "Literal too large for BASE=16");
        static_assert( BASE!=10 || sizeof...(Cs) <=  39-1, "Literal too large for BASE=10");
        static_assert( BASE!=8  || sizeof...(Cs) <=  44-1, "Literal too large for BASE=8");
        static_assert( BASE!=2  || sizeof...(Cs) <= 128-1, "Literal too large for BASE=2");
        return lit_eval<BASE, BASE*V + hexval(C), Cs...>();
    }

    template<char... Cs > struct LitEval 
    {static constexpr uint_xxl_t eval() {return lit_eval<10,0,Cs...>();} };

    template<char... Cs> struct LitEval<'0','x',Cs...> 
    {static constexpr uint_xxl_t eval() {return lit_eval<16,0,Cs...>();} };

    template<char... Cs> struct LitEval<'0','b',Cs...> 
    {static constexpr uint_xxl_t eval() {return lit_eval<2,0,Cs...>();} };

    template<char... Cs> struct LitEval<'0',Cs...> 
    {static constexpr uint_xxl_t eval() {return lit_eval<8,0,Cs...>();} };

    template<char... Cs> 
    constexpr uint_xxl_t operator "" _xxl() {return LitEval<Cs...>::eval();}
}

template<char... Cs> 
constexpr uint_xxl_t operator "" _xxl() {return ::detail_xxl::operator "" _xxl<Cs...>();}

#endif // __SIZEOF_INT128__

It can be used in constexpr just like normal integer constants:

static_assert(   0_xxl == 0, "_xxl error" );
static_assert( 0b0_xxl == 0, "_xxl error" );
static_assert(  00_xxl == 0, "_xxl error" );
static_assert( 0x0_xxl == 0, "_xxl error" );

static_assert(   1_xxl == 1, "_xxl error" );
static_assert( 0b1_xxl == 1, "_xxl error" );
static_assert(  01_xxl == 1, "_xxl error" );
static_assert( 0x1_xxl == 1, "_xxl error" );

static_assert(      2_xxl == 2, "_xxl error" );
static_assert(   0b10_xxl == 2, "_xxl error" );
static_assert(     02_xxl == 2, "_xxl error" );
static_assert(    0x2_xxl == 2, "_xxl error" );

static_assert(      9_xxl == 9, "_xxl error" );
static_assert( 0b1001_xxl == 9, "_xxl error" );
static_assert(    011_xxl == 9, "_xxl error" );
static_assert(    0x9_xxl == 9, "_xxl error" );

static_assert(     10_xxl == 10, "_xxl error" );
static_assert(    0xa_xxl == 10, "_xxl error" );
static_assert(    0xA_xxl == 10, "_xxl error" );

static_assert( 0xABCDEF_xxl == 0xABCDEF, "_xxl error" );
static_assert( 1122334455667788_xxl == 1122334455667788LLu, "_xxl error" );
static_assert(0x80000000000000000000000000000000_xxl >> 126 == 0b10, "_xxl error");
static_assert(0x80000000000000000000000000000000_xxl >> 127 == 0b01, "_xxl error");
static_assert( 0xF000000000000000B000000000000000_xxl > 0xB000000000000000, "_xxl error" );

How to handle 128-bit unsigned integer in C++14, AFAICT, 128 bit integers are not a standard specification in C++ 14 or any other versions. This means you have 3 choices: Use a compiler (such as GCC or� Microsoft C also permits the declaration of sized integer variables, which are integral types of size 8-, 16-, 32- or 64-bits. For more information on sized integers in C, see Sized Integer Types.

If there is 128-bit integer type introduce in the C++ standard, what , If there is 128-bit integer type introduce in the C++ standard, what would it be called as a general name? 5 Answers. Pawel Kraszewski, Former academic� CHAR_BIT 8 Defines the number of bits in a byte. SCHAR_MIN-128 Defines the minimum value for a signed char. SCHAR_MAX +127 Defines the maximum value for a signed char. UCHAR_MAX 255 Defines the maximum value for an unsigned char. CHAR_MIN-128 Defines the minimum value for type char and its value

128-bit integers — libcork 0.14.0 documentation, We provide an API for working with unsigned, 128-bit integers. The result is a valid lvalue, so you can assign to it to update the contents of value: cork_u128 b = cork_u128_from_32(0, 3); cork_u128 c = cork_u128_add(a, b); cork_u128 d � long double: Real floating-point type, usually mapped to an extended precision floating-point number format. Actual properties unspecified. It can be either x86 extended-precision floating-point format (80 bits, but typically 96 bits or 128 bits in memory with padding bytes), the non-IEEE "double-double" (128 bits), IEEE 754 quadruple-precision floating-point format (128 bits), or the same as

Solved, Look at the actual definition of these 128 bit integers (I found it in sdp.h). for the C compiler, you will have to use some other method to assign� If the left-hand operand is of type int or long, the right-shift operator performs an arithmetic shift: the value of the most significant bit (the sign bit) of the left-hand operand is propagated to the high-order empty bit positions. That is, the high-order empty bit positions are set to zero if the left-hand operand is non-negative and set to

Comments
  • Also see "Why isn't there int128_t?" answer.
  • ((__uint128_t)47942806*1000000+932686)*1000000+753431
  • BTW, you should probably replace instances of __uint128_t with unsigned __int128. The former appears to be 'deprecated'.
  • "When I try to assign an 128 bit integer" Whoops, nope, that's not what you're doing. You're trying to assign to an 128 bit integer, but the thing you're assigning to it is not one!
  • There are 128 bit integers now? Right. 128-bit. Exponential growth. Is this to do with encryption?!
  • Maybe "cannot have 128 bit integer constants, unless your intmax_t is at least 128 bit wide"?
  • I'm not sure. The quoted docs mention "long long integer" type specifically.
  • In reader the C11 draft spec, it is clear that integer constants must have at least the range of long long/unsigned long long. It is not clear if integer constants must have at least the range of intmax_t/uintmax_t. I would think it would be required.
  • @chux, these types are extensions and not covered by the standard. For the intmax_t types the standard provides the corresponding macros INTMAX_C that are guaranteed to create constants of the correct type.
  • @el.pescado, while there is no direct support, you still can have constant expressions of that type. E.g ((__int128_t)1000000000000*HIGH)+LOW could be a way of constructing such an expression for a large value, where HIGH and LOW are the higher and lower digits of the number.
  • Is this intended to be a joke?
  • Even assuming the string value is correct for whatever endianness is needed, that will likely result in a SIGBUS for any architecture that has alignment restrictions on __int128 variables.
  • I found it actually works for gcc 5.2.0 on x86_64. Even with int n = *(int*) "1234";. Maybe Andrew is right. The string constant is not guaranteed to be aligned and thus this trick may not work on archs other than x86.
  • @jerry73204 : in my case, the compiler is complaining in C99 about the pointer with error: expression must have a constant value __int128 llong_min=(*((char *){"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfd"})); ^