Cuando trato de asignar un entero de 128 bits en gcc 4.9.1, obtengo un warning: integer constant is too large for its type
.
Código de ejemplo
int main(void) {
__uint128_t p = 47942806932686753431;
return 0;
}
Producción
estoy compilando con gcc -std=c11 -o test test.c
y obtengo:
test.c: In function ‘main’:
test.c:2:19: warning: integer constant is too large for its type
__uint128_t p = 47942806932686753431;
^
¿Estoy haciendo algo mal o es un error en gcc?
¿Estoy haciendo algo mal o es un error en gcc?
el problema esta en 47942806932686753431
parte, no en __uint128_t p
. De acuerdo a documentos gcc no hay forma de declarar una constante de 128 bits:
GCC no admite la expresión de una constante entera de tipo __int128 para destinos con enteros largos de menos de 128 bits de ancho.
Entonces, parece que si bien puedes tener 128 bits Variablesno puedes tener 128 bits constantesa menos que su long long
es de 128 bits de ancho.
La solución podría ser construir un valor de 128 bits a partir de constantes integrales “más estrechas” usando operaciones aritméticas básicas, y esperar que el compilador funcione plegado constante.
¿Has probado esto?
__int128 p = *(__int128*) "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
EDITAR 25 de noviembre
Perdón por la mala aclaración en la publicación anterior. En serio, no publiqué esta respuesta como una broma. Aunque el documento de GCC establece que no hay forma de expresar una constante entera de 128 bits, esta publicación simplemente proporciona una solución alterna para aquellos que quieren asignar valores a las variables __uint128_t con facilidad.
Puede intentar compilar el siguiente código con GCC (7.2.0) o Clang (5.0.0). Imprime los resultados deseados.
#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;
}
La salida estándar:
HIGH 0f0e0d0c0b0a0908
LOW 0706050403020100
Esto solo se considera como un solución alterna ya que juega trucos con los punteros al colocar el “valor” en la sección .rodata (si lo objdump), y no es portátil (x86_64 y aarch64 están bien pero no arm y x86). Creo que ha sido suficiente para quienes codifican en máquinas de escritorio.
Tuve el mismo problema y preparé una solución usando literales definidos por el usuario. Así es como crea una instancia del literal _xxl definido por el usuario:
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;
}
Producción:
sizeof(a): 8
sizeof(b): 16
a == 0? true
b == 0? false
b >> 124 = f
Aquí está la implementación para el literal definido por el usuario _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__
Se puede usar en constexpr como constantes enteras normales:
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" );
Consulte también “¿Por qué no hay int128_t?” responder.
– chux – Reincorporar a Monica
16 de julio de 2015 a las 18:13
((__uint128_t)47942806*1000000+932686)*1000000+753431
– Marc Glisse
16 de julio de 2015 a las 18:15
Por cierto, probablemente deberías reemplazar las instancias de
__uint128_t
conunsigned __int128
. El primero parece estar ‘obsoleto’.– Brett Hale
16 de julio de 2015 a las 19:26
“Cuando trato de asignar un número entero de 128 bits” Vaya, no, eso no es lo que estás haciendo. Estás tratando de asignar para un entero de 128 bits, ¡pero lo que le estás asignando no es uno!
– Carreras de ligereza en órbita
25/10/2015 a las 15:29
¿Hay números enteros de 128 bits ahora? Derecha. 128 bits. Crecimiento exponencial. ¿Esto tiene que ver con el cifrado?
–Steve Woods
13 de julio de 2018 a las 13:20