128-Bit-Integer in C zuweisen

Lesezeit: 7 Minuten

Wenn ich versuche, in gcc 4.9.1 eine 128-Bit-Ganzzahl zuzuweisen, erhalte ich a warning: integer constant is too large for its type.

Beispielcode

int main(void) {
  __uint128_t p = 47942806932686753431;

  return 0;
}

Ausgabe

Ich kompiliere mit gcc -std=c11 -o test test.c und ich bekomme:

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

Mache ich etwas falsch oder ist das ein Fehler in gcc?

  • Siehe auch “Warum gibt es kein int128_t?” Antworten.

    – chux – Wiedereinsetzung von Monica

    16. Juli 2015 um 18:13 Uhr

  • ((__uint128_t)47942806*1000000+932686)*1000000+753431

    – Marc Glisse

    16. Juli 2015 um 18:15 Uhr

  • Übrigens, Sie sollten wahrscheinlich Instanzen von ersetzen __uint128_t mit unsigned __int128. Ersteres scheint “veraltet” zu sein.

    – Brett Hale

    16. Juli 2015 um 19:26 Uhr

  • “Wenn ich versuche, eine 128-Bit-Ganzzahl zuzuweisen” Ups, nein, das machst du nicht. Sie versuchen zuzuordnen zu eine 128-Bit-Ganzzahl, aber das, was Sie ihr zuweisen, ist keine!

    – Leichtigkeitsrennen im Orbit

    25. Oktober 2015 um 15:29 Uhr

  • Gibt es jetzt 128-Bit-Ganzzahlen? Recht. 128-Bit. Exponentielles Wachstum. Hat das mit Verschlüsselung zu tun?!

    – Steve Woods

    13. Juli 2018 um 13:20 Uhr


Benutzer-Avatar
el.pescado – нет войне

Mache ich etwas falsch oder ist das ein Fehler in gcc?

Das Problem ist drin 47942806932686753431 Teil, nicht drin __uint128_t p. Entsprechend gcc-Dokumente Es gibt keine Möglichkeit, eine 128-Bit-Konstante zu deklarieren:

Es gibt keine Unterstützung in GCC zum Ausdrücken einer Integer-Konstante des Typs __int128 für Ziele mit Long-Long-Integer mit einer Breite von weniger als 128 Bit.

Es scheint also, dass Sie 128 Bit haben können VariablenSie können keine 128-Bit haben Konstantenes sei denn, Ihre long long ist 128 Bit breit.

Die Problemumgehung könnte darin bestehen, einen 128-Bit-Wert aus “schmaleren” ganzzahligen Konstanten unter Verwendung grundlegender arithmetischer Operationen zu konstruieren und auf die Ausführung des Compilers zu hoffen ständiges Falten.

  • Vielleicht “können keine 128-Bit-Ganzzahlkonstanten haben, es sei denn, Ihre intmax_t ist mindestens 128 Bit breit”?

    – chux – Wiedereinsetzung von Monica

    16. Juli 2015 um 18:07 Uhr


  • Ich bin mir nicht sicher. Die zitierten Dokumente erwähnen speziell den Typ “Long Long Integer”.

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

    16. Juli 2015 um 18:14 Uhr

  • Im Reader des C11-Spezifikationsentwurfs ist das klar ganzzahlige Konstanten muss mindestens die Reichweite von haben long long/unsigned long long. Es ist nicht klar, ob ganzzahlige Konstanten muss mindestens die Reichweite von haben intmax_t/uintmax_t. Ich würde denken es wäre erforderlich.

    – chux – Wiedereinsetzung von Monica

    16. Juli 2015 um 18:32 Uhr

  • @chux, diese Typen sind Erweiterungen und nicht vom Standard abgedeckt. Für die intmax_t Typen stellt der Standard die entsprechenden Makros zur Verfügung INTMAX_C die garantiert Konstanten des richtigen Typs erstellen.

    – Jens Gustedt

    16. Juli 2015 um 18:48 Uhr

  • @el.pescado, obwohl es keine direkte Unterstützung gibt, können Sie dennoch konstante Ausdrücke dieses Typs haben. Z.B ((__int128_t)1000000000000*HIGH)+LOW könnte eine Möglichkeit sein, einen solchen Ausdruck für einen großen Wert zu konstruieren, wo HIGH und LOW sind die oberen und unteren Ziffern der Zahl.

    – Jens Gustedt

    16. Juli 2015 um 18:51 Uhr


Benutzer-Avatar
jerry73204

Hast du das versucht?

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

BEARBEITEN 25. November

Entschuldigung für die schlechte Klarstellung im vorherigen Beitrag. Im Ernst, ich habe diese Antwort nicht als Witz gepostet. Obwohl das GCC-Dokument besagt, dass es keine Möglichkeit gibt, eine 128-Bit-Ganzzahlkonstante auszudrücken, bietet dieser Beitrag einfach eine Problemumgehung für diejenigen, die __uint128_t-Variablen mit Leichtigkeit Werte zuweisen möchten.

Sie können versuchen, den folgenden Code mit GCC (7.2.0) oder Clang (5.0.0) zu kompilieren. Es druckt die gewünschten Ergebnisse.

#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;
}

Die Standardausgabe:

HIGH 0f0e0d0c0b0a0908
LOW  0706050403020100

Dies gilt nur als Problemumgehung da es Zeigern Streiche spielt, indem es den “Wert” in den .rodata-Abschnitt platziert (wenn Sie es objdump), und es nicht portabel ist (x86_64 und aarch64 sind in Ordnung, aber nicht arm und x86). Ich denke, es war genug für diejenigen, die auf Desktop-Computern programmieren.

  • Soll das ein Scherz sein?

    – Leichtigkeitsrennen im Orbit

    25. Oktober 2015 um 15:29 Uhr

  • Selbst wenn der Zeichenfolgenwert für die erforderliche Endianness korrekt ist, führt dies wahrscheinlich zu a SIGBUS für jede Architektur, die Ausrichtungsbeschränkungen hat __int128 Variablen.

    – Andreas Henle

    25. Oktober 2015 um 15:33 Uhr


  • Ich fand, dass es tatsächlich für gcc 5.2.0 auf x86_64 funktioniert. Sogar mit int n = *(int*) "1234";. Vielleicht hat Andreas recht. Es ist nicht garantiert, dass die Zeichenfolgenkonstante ausgerichtet ist, und daher funktioniert dieser Trick möglicherweise nicht auf anderen Archs als x86.

    – jerry73204

    27. Oktober 2015 um 7:05 Uhr


  • @ jerry73204: In meinem Fall beschwert sich der Compiler C99 über den Zeiger mit 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"})); ^

    – Benutzer2284570

    15. Juni 2020 um 23:58 Uhr


  • Abgesehen von der Ausrichtung hat die Lösung in dieser Antwort auch Probleme mit striktem Aliasing, aber so etwas wie __uint128_t q = (union { unsigned char r[16]; __uint128_t i; }) {00,01,02,03,04,05,06,07,8,9,0xa,0xb,0xc,0xd,0xe,0xf}.i; funktioniert. Es nimmt die Endianness und die Breite von an char als 8 Bit, aber auch die Antwort über diesem Kommentar.

    – Pascal Cuoq

    19. Oktober 2020 um 11:20 Uhr


Ich hatte das gleiche Problem und habe mir eine Lösung mit benutzerdefinierten Literalen ausgedacht. So instanziieren Sie das benutzerdefinierte 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;
}

Ausgabe:

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

Hier ist die Implementierung für das benutzerdefinierte 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__

Sie kann in constexpr wie normale Integer-Konstanten verwendet werden:

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" );

  • Danke für die Antwort und für Ihre Zeit, aber Ihr Code ist C++, nicht C.

    – iblau

    27. Dezember 2019 um 9:25 Uhr

  • ups… das ist mir nicht aufgefallen

    – Fabio Fernandes

    28. Dezember 2019 um 11:25 Uhr

  • Trotzdem schöne Antwort

    – étale-Kohomologie

    21. April um 2:07 Uhr

1367700cookie-check128-Bit-Integer in C zuweisen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy