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?
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.
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.
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" );
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
mitunsigned __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