C에서 128비트 정수 할당
gcc 4.9.1에서 128비트 정수를 할당하려고 하면 다음과 같은 메시지가 나타납니다.warning: integer constant is too large for its type
.
예제 코드
int main(void) {
__uint128_t p = 47942806932686753431;
return 0;
}
산출량
저는 저와 함께 편집하고 있습니다.gcc -std=c11 -o test test.c
알 수 있습니다.
test.c: In function ‘main’:
test.c:2:19: warning: integer constant is too large for its type
__uint128_t p = 47942806932686753431;
^
제가 뭔가 잘못하고 있는 건가요 아니면 이게 gcc의 버그인가요?
제가 뭔가 잘못하고 있는 건가요 아니면 이게 gcc의 버그인가요?
문제는 에 있습니다.47942806932686753431
부분이 아닌__uint128_t p
. gcc 문서에 따르면 128비트 상수를 선언할 수 있는 방법은 없습니다.
GCC에서는 128비트 너비보다 긴 긴 정수의 대상에 대해 유형 __int128의 정수 상수를 표현할 수 없습니다.
따라서 128비트 변수는 사용할 수 있지만 128비트 상수는 사용하지 않는 한 사용할 수 없습니다.long long
128비트 너비입니다.
해결 방법은 기본 산술 연산을 사용하여 "더 좁은" 적분 상수에서 128 비트 값을 구성하고 컴파일러가 상수 접기를 수행하기를 희망하는 것입니다.
이거 먹어봤어요?
__int128 p = *(__int128*) "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
편집 11월 25일
이전 게시물에 대한 해명이 잘 되지 않아 죄송합니다.진짜로 장난삼아 올린 답이 아닙니다.GCC 문서에는 128비트 정수 상수를 표현할 방법이 없다고 나와 있지만, 이 게시물은 __uint128_t 변수에 값을 쉽게 할당하려는 사람들에게 해결책을 제공할 뿐입니다.
GCC(7.2.0) 또는 Clang(5.0.0)을 사용하여 아래의 코드를 컴파일 할 수 있습니다.원하는 결과를 인쇄합니다.
#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;
}
stdout:
HIGH 0f0e0d0c0b0a0908
LOW 0706050403020100
이는 .rodata 섹션에 "값"을 배치하여 포인터에 장난을 치기 때문에(objdumping을 하는 경우), 휴대용이 아닙니다(x86_64 및 arch64는 괜찮지만 arm 및 x86은 아닙니다).데스크톱 컴퓨터에서 코딩하는 것만으로도 충분하다고 생각합니다.
두 개의 64비트 값을 결합하는 간단한 매크로를 제안합니다.
#define UINT128(hi, lo) (((__uint128_t) (hi)) << 64 | (lo))
사용 예시:
#include <stdint.h>
#include <stdio.h>
#define UINT128(hi, lo) (((__uint128_t) (hi)) << 64 | (lo))
int main() {
// Creates constant 0x010203040506070890a0b0c0d0e0f10
__uint128_t x = UINT128(0x0102030405060708, 0x090a0b0c0d0e0f10);
// Prints 1, 2, 3, 4, .. 15, 16
for (int i = 0; i < 16; ++i) {
printf("%d ", (int)((x >> (120 - 8*i)) & 255));
}
printf("\n");
}
또는 0x 접두사를 매크로(권장되지 않음)로 이동할 수도 있습니다.
#define UINT128(hi, lo) (((__uint128_t) (0x##hi)) << 64 | (0x##lo))
할 수 있습니다.UINT128(0102030405060708, 090a0b0c0d0e0f10)
약간 짧긴 하지만 구문 강조를 엉망으로 만들 수도 있습니다.0102030405060708
팔분상수로 잘못 해석될 수도 있고,090a0b0c0d0e0f10
그 자체로는 유효한 토큰이 아니기 때문에 이를 추천하고 싶지 않습니다.
저도 같은 문제가 있었고 사용자 정의 리터럴을 사용하여 해결책을 마련했습니다.사용자 정의 리터럴을 인스턴스화하는 방법은 다음과 같습니다._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;
}
출력:
sizeof(a): 8
sizeof(b): 16
a == 0? true
b == 0? false
b >> 124 = f
다음은 사용자 정의 리터럴에 대한 구현입니다._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__
에 사용할 수 있습니다.constexpr
일반 정수 상수와 마찬가지로:
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" );
언급URL : https://stackoverflow.com/questions/31461318/assigning-128-bit-integer-in-c
'programing' 카테고리의 다른 글
Jquery에서 인덱스별로 하위 요소를 얻는 방법은? (0) | 2023.09.20 |
---|---|
TSQL 문의 유효성을 프로그래밍 방식으로 확인(파싱)하려면 어떻게 해야 합니까? (0) | 2023.09.20 |
Visual Studio 2010에 64비트에 대한 #정의가 있습니까? (0) | 2023.09.20 |
내부 텍스트별 XPath 선택 (0) | 2023.09.20 |
SQLite3 및 여러 프로세스 (0) | 2023.09.20 |