[c] C 빅 엔디안 또는 리틀 엔디안 머신을 결정하는 매크로 정의?

기계의 엔디안을 결정하는 한 줄 매크로 정의가 있습니까? 다음 코드를 사용하고 있지만 매크로로 변환하면 너무 길어집니다.

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 문서 를 참조하십시오.