컴파일 타임에 엔디안 결정
내 프로그램이 컴파일되는 플랫폼의 엔디안을 (컴파일 시간 동안) 결정하는 안전하고 이식 가능한 방법이 있습니까? 저는 C로 쓰고 있습니다.
[편집] 답변 주셔서 감사합니다. 저는 런타임 솔루션을 고수하기로 결정했습니다!
이것은 컴파일 시간 확인을위한 것입니다.
endian.hpp많은 플랫폼을 포함 하는 부스트 헤더 파일의 정보를 사용할 수 있습니다 .
런타임 검사를 위해 편집
bool isLittleEndian()
{
short int number = 0x1;
char *numPtr = (char*)&number;
return (numPtr[0] == 1);
}
정수를 만들고 첫 번째 바이트 (최하위 바이트)를 읽습니다. 그 바이트가 1이면 시스템은 리틀 엔디안이고 그렇지 않으면 빅 엔디안입니다.
편집 생각
예, 일부 플랫폼 (아무것도 생각할 수 없음)에서 잠재적 인 문제가 발생할 수 있습니다 sizeof(char) == sizeof(short int). 에서 사용할 수있는 고정 너비 다중 바이트 정수 유형을 사용할 수 있습니다 <stdint.h>. 또는 플랫폼에없는 경우 다시 사용하도록 부스트 헤더를 조정할 수 있습니다.stdint.hpp
컴파일 시간 검사 의 원래 질문에 답하기 위해 기존 및 모든 향후 컴파일러에서 작동하는 표준화 된 방법이 없습니다. 기존 C, C ++ 및 POSIX 표준 중 어느 것도 엔디안 감지를위한 매크로를 정의하지 않기 때문입니다.
그러나 알려진 컴파일러 세트로 제한하려는 경우 각 컴파일러의 문서를 검색하여 엔디안을 정의하는 데 사용하는 사전 정의 된 매크로 (있는 경우)를 찾을 수 있습니다. 이 페이지 에는 찾을 수있는 여러 매크로가 나열되어 있으므로 여기에 해당하는 몇 가지 코드가 있습니다.
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \
defined(__BIG_ENDIAN__) || \
defined(__ARMEB__) || \
defined(__THUMBEB__) || \
defined(__AARCH64EB__) || \
defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
// It's a big-endian target architecture
#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \
defined(__LITTLE_ENDIAN__) || \
defined(__ARMEL__) || \
defined(__THUMBEL__) || \
defined(__AARCH64EL__) || \
defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__)
// It's a little-endian target architecture
#else
#error "I don't know what architecture this is!"
#endif
컴파일러가 문서에서 사용하는 사전 정의 된 매크로를 찾을 수없는 경우 사전 정의 된 매크로의 전체 목록을 뱉어 내고 거기에서 작동 할 것을 추측하도록 강제 할 수도 있습니다 (ENDIAN, ORDER 또는 프로세서로 무엇이든 찾으십시오). 아키텍처 이름). 이 페이지 에는 여러 컴파일러에서이를 수행하는 여러 메소드가 나열되어 있습니다.
Compiler C macros C++ macros
Clang/LLVM clang -dM -E -x c /dev/null clang++ -dM -E -x c++ /dev/null
GNU GCC/G++ gcc -dM -E -x c /dev/null g++ -dM -E -x c++ /dev/null
Hewlett-Packard C/aC++ cc -dM -E -x c /dev/null aCC -dM -E -x c++ /dev/null
IBM XL C/C++ xlc -qshowmacros -E /dev/null xlc++ -qshowmacros -E /dev/null
Intel ICC/ICPC icc -dM -E -x c /dev/null icpc -dM -E -x c++ /dev/null
Microsoft Visual Studio (none) (none)
Oracle Solaris Studio cc -xdumpmacros -E /dev/null CC -xdumpmacros -E /dev/null
Portland Group PGCC/PGCPP pgcc -dM -E (none)
마지막으로,이를 마무리하기 위해 Microsoft Visual C / C ++ 컴파일러는 이상하며 위의 어떤 것도 포함하지 않습니다. 다행히도 여기에 미리 정의 된 매크로를 문서화했으며 대상 프로세서 아키텍처를 사용하여 엔디안을 추론 할 수 있습니다. Windows에서 현재 지원되는 모든 프로세서가 (리틀 엔디안하지만 _M_IX86, _M_X64, _M_IA64,하고 _M_ARM있는 리틀 엔디안), 파워 PC 같은 몇 가지 역사적으로 지원되는 프로세서는 ( _M_PPC) 빅 엔디안했다. 그러나 더 관련이있는 것은 Xbox 360은 빅 엔디안 PowerPC 시스템이므로 크로스 플랫폼 라이브러리 헤더를 작성하는 경우 _M_PPC.
C99를 사용하면 다음과 같이 검사를 수행 할 수 있습니다.
#define I_AM_LITTLE (((union { unsigned x; unsigned char c; }){1}).c)
같은 조건 if (I_AM_LITTLE)은 컴파일 타임에 평가되고 컴파일러가 전체 블록을 최적화 할 수 있도록합니다.
이것이 C99 의 상수 표현식 (정적 저장 기간 데이터의 이니셜 라이저에서 사용할 수 있음)을 엄격하게 말하는지 여부에 대한 참조는 없지만 그렇지 않은 경우 차선책입니다.
C FAQ 에서 흥미로운 읽기 :
당신은 아마 할 수 없습니다. 엔디안을 감지하는 일반적인 기술은 포인터 또는 char 배열 또는 공용체를 포함하지만 전 처리기 산술은 긴 정수만 사용하며 주소 지정 개념이 없습니다. 또 다른 유혹적인 가능성은 다음과 같습니다.
#if 'ABCD' == 0x41424344그러나 이것도 신뢰할 수 없습니다.
constexprC ++ 기능 제공에 대한 답변을 확장하고 싶습니다.
union Mix {
int sdat;
char cdat[4];
};
static constexpr Mix mix { 0x1 };
constexpr bool isLittleEndian() {
return mix.cdat[0] == 1;
}
Since mix is constexpr too it is compile time and can be used in constexpr bool isLittleEndian(). Should be safe to use.
Update
As @Cheersandhth pointed out below, these seems to be problematic.
The reason is, that it is not C++11-Standard conform, where type punning is forbidden. There can always only one union member be active at a time. With a standard conforming compiler you will get an error.
So, don't use it in C++. It seems, you can do it in C though. I leave my answer in for educational purposes :-) and because the question is about C...
Update 2
This assumes that int has the size of 4 chars, which is not always given as @PetrVepřek correctly pointed out below. To make your code truly portable you have to be more clever here. This should suffice for many cases though. Note that sizeof(char) is always 1, by definition. The code above assumes sizeof(int)==4.
Not during compile time, but perhaps during runtime. Here's a C function I wrote to determine endianness:
/* Returns 1 if LITTLE-ENDIAN or 0 if BIG-ENDIAN */
#include <inttypes.h>
int endianness()
{
union { uint8_t c[4]; uint32_t i; } data;
data.i = 0x12345678;
return (data.c[0] == 0x78);
}
From Finally, one-line endianness detection in the C preprocessor:
#include <stdint.h>
#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100)
Any decent optimizer will resolve this at compile-time. gcc does at -O1.
Of course stdint.h is C99. For ANSI/C89 portability see Doug Gwyn's Instant C9x library.
I once used a construct like this one:
uint16_t HI_BYTE = 0,
LO_BYTE = 1;
uint16_t s = 1;
if(*(uint8_t *) &s == 1) {
HI_BYTE = 1;
LO_BYTE = 0;
}
pByte[HI_BYTE] = 0x10;
pByte[LO_BYTE] = 0x20;
gcc with -O2 was able to make it completely compile time. That means, the HI_BYTE and LO_BYTE variables were replaced entirely and even the pByte acces was replaced in the assembler by the equivalent of *(unit16_t *pByte) = 0x1020;.
It's as compile time as it gets.
To my knowledge no, not during compile time.
At run-time, you can do trivial checks such as setting a multi-byte value to a known bit string and inspect what bytes that results in. For instance using a union,
typedef union {
uint32_t word;
uint8_t bytes[4];
} byte_check;
or casting,
uint32_t word;
uint8_t * bytes = &word;
Please note that for completely portable endianness checks, you need to take into account both big-endian, little-endian and mixed-endian systems.
Use CMake TestBigEndian as
INCLUDE(TestBigEndian)
TEST_BIG_ENDIAN(ENDIAN)
IF (ENDIAN)
# big endian
ELSE (ENDIAN)
# little endian
ENDIF (ENDIAN)
참고URL : https://stackoverflow.com/questions/4239993/determining-endianness-at-compile-time
'IT Share you' 카테고리의 다른 글
| 일치가 재귀 적이 지 않도록 .gitignore에 무언가를 추가하는 방법은 무엇입니까? (0) | 2020.12.11 |
|---|---|
| .NET 4.0의 Entity Framework와 LINQ to SQL의 차이점은 무엇입니까? (0) | 2020.12.11 |
| Python 클래스 메서드의 사용 사례의 예는 무엇입니까? (0) | 2020.12.11 |
| IE8의 CSS 둥근 모서리 (0) | 2020.12.11 |
| MySQL에서 CASE..WHEN을 올바르게 사용하는 방법 (0) | 2020.12.11 |