기계의 엔디안을 결정하는 한 줄 매크로 정의가 있습니까? 다음 코드를 사용하고 있지만 매크로로 변환하면 너무 길어집니다.
unsigned char test_endian( void )
{
int test_var = 1;
unsigned char *test_endian = (unsigned char*)&test_var;
return (test_endian[0] == 0);
}
답변
임의의 바이트 순서를 지원하는 코드로 다음과 같은 파일에 넣을 준비가되었습니다 order32.h
.
#ifndef ORDER32_H
#define ORDER32_H
#include <limits.h>
#include <stdint.h>
#if CHAR_BIT != 8
#error "unsupported char size"
#endif
enum
{
O32_LITTLE_ENDIAN = 0x03020100ul,
O32_BIG_ENDIAN = 0x00010203ul,
O32_PDP_ENDIAN = 0x01000302ul, /* DEC PDP-11 (aka ENDIAN_LITTLE_WORD) */
O32_HONEYWELL_ENDIAN = 0x02030001ul /* Honeywell 316 (aka ENDIAN_BIG_WORD) */
};
static const union { unsigned char bytes[4]; uint32_t value; } o32_host_order =
{ { 0, 1, 2, 3 } };
#define O32_HOST_ORDER (o32_host_order.value)
#endif
다음을 통해 리틀 엔디안 시스템을 확인합니다.
O32_HOST_ORDER == O32_LITTLE_ENDIAN
답변
C99 복합 리터럴을 지원하는 컴파일러가있는 경우 :
#define IS_BIG_ENDIAN (!*(unsigned char *)&(uint16_t){1})
또는:
#define IS_BIG_ENDIAN (!(union { uint16_t u16; unsigned char c; }){ .u16 = 1 }.c)
그러나 일반적으로 호스트 플랫폼의 엔디안에 의존하지 않는 코드를 작성해야합니다.
호스트 엔디안 독립 구현 예 ntohl()
:
uint32_t ntohl(uint32_t n)
{
unsigned char *np = (unsigned char *)&n;
return ((uint32_t)np[0] << 24) |
((uint32_t)np[1] << 16) |
((uint32_t)np[2] << 8) |
(uint32_t)np[3];
}
답변
표준 <endian.h>
은 없지만를 포함한 많은 시스템 에서 찾을 수있는 몇 가지 정의를 제공합니다.
답변
런타임에 엔디안을 감지하려면 메모리를 참조 할 수 있어야합니다. 표준 C를 고수하는 경우 메모리에서 변수를 선언하려면 문이 필요하지만 값을 반환하려면식이 필요합니다. 단일 매크로에서이 작업을 수행하는 방법을 모르겠습니다. 이것이 gcc에 확장자가있는 이유입니다. 🙂
.h 파일을 갖고 싶다면 다음을 정의 할 수 있습니다.
static uint32_t endianness = 0xdeadbeef;
enum endianness { BIG, LITTLE };
#define ENDIANNESS ( *(const char *)&endianness == 0xef ? LITTLE \
: *(const char *)&endianness == 0xde ? BIG \
: assert(0))
그런 다음 원하는대로 ENDIANNESS
매크로를 사용할 수 있습니다 .
답변
전처리기에 만 의존하려면 미리 정의 된 기호 목록을 찾아야합니다. 전 처리기 산술에는 주소 지정 개념이 없습니다.
Mac의 GCC 는 __LITTLE_ENDIAN__
또는__BIG_ENDIAN__
$ gcc -E -dM - < /dev/null |grep ENDIAN
#define __LITTLE_ENDIAN__ 1
그런 다음 #ifdef _WIN32
등 플랫폼 감지를 기반으로 더 많은 전 처리기 조건 지시문을 추가 할 수 있습니다 .
답변
나는 이것이 요구 된 것이라고 믿는다. 나는 msvc 아래의 little endian 시스템에서만 이것을 테스트했습니다. 누군가가 빅 엔디안 머신에서 확인합니다.
#define LITTLE_ENDIAN 0x41424344UL
#define BIG_ENDIAN 0x44434241UL
#define PDP_ENDIAN 0x42414443UL
#define ENDIAN_ORDER ('ABCD')
#if ENDIAN_ORDER==LITTLE_ENDIAN
#error "machine is little endian"
#elif ENDIAN_ORDER==BIG_ENDIAN
#error "machine is big endian"
#elif ENDIAN_ORDER==PDP_ENDIAN
#error "jeez, machine is PDP!"
#else
#error "What kind of hardware is this?!"
#endif
부수적으로 (컴파일러 별), 공격적인 컴파일러를 사용하면 “데드 코드 제거”최적화를 사용하여 다음과 같은 컴파일 시간 #if
과 동일한 효과를 얻을 수 있습니다.
unsigned yourOwnEndianSpecific_htonl(unsigned n)
{
static unsigned long signature= 0x01020304UL;
if (1 == (unsigned char&)signature) // big endian
return n;
if (2 == (unsigned char&)signature) // the PDP style
{
n = ((n << 8) & 0xFF00FF00UL) | ((n>>8) & 0x00FF00FFUL);
return n;
}
if (4 == (unsigned char&)signature) // little endian
{
n = (n << 16) | (n >> 16);
n = ((n << 8) & 0xFF00FF00UL) | ((n>>8) & 0x00FF00FFUL);
return n;
}
// only weird machines get here
return n; // ?
}
위는 완전히 내 코드를 제거, 컴파일러는 컴파일시에 상수 값을 인식한다는 사실에 의존 if (false) { ... }
와 같은 대체합니다 코드 if (true) { foo(); }
와 foo();
최악의 시나리오 : 최적화를하지 않는 컴파일러는, 당신은 여전히 약간 느린 올바른 코드 만 얻을.
답변
컴파일 시간 테스트를 찾고 있고 gcc를 사용하는 경우 다음을 수행 할 수 있습니다.
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
자세한 정보는 gcc 문서 를 참조하십시오.