C ++ 프로그램에서 프로그래밍 방식으로 엔디안 감지 또는 리틀 엔디안 아키텍처인지 여부를 감지하는

빅 엔디안 또는 리틀 엔디안 아키텍처인지 여부를 감지하는 프로그래밍 방식이 있습니까? 인텔 또는 PPC 시스템에서 실행될 코드를 작성하고 정확히 동일한 코드를 사용해야합니다 (예 : 조건부 컴파일 없음).



답변

유형 punning을 기반으로 한 메소드가 마음에 들지 않습니다. 종종 컴파일러가 경고합니다. 그것이 바로 노조를위한 것입니다!

bool is_big_endian(void)
{
    union {
        uint32_t i;
        char c[4];
    } bint = {0x01020304};

    return bint.c[0] == 1;
}

원칙은 다른 사람들이 제안한 유형의 경우와 동일하지만 더 명확하며 C99에 따르면 정확합니다. gcc는 이것을 직접 포인터 캐스트와 비교하여 선호합니다.

이것은 컴파일 타임에 엔디안을 수정하는 것보다 훨씬 낫습니다-다중 아키텍처 (예 : Mac OS x의 지방 이진)를 지원하는 OS의 경우 ppc / i386 모두에서 작동하지만 다른 방법으로는 엉망이되기 쉽습니다. .


답변

int를 설정하고 비트를 마스킹하여이를 수행 할 수 있지만 가장 쉬운 방법은 내장 네트워크 바이트 변환 ops를 사용하는 것입니다 (네트워크 바이트 순서는 항상 큰 엔디안이므로).

if ( htonl(47) == 47 ) {
  // Big endian
} else {
  // Little endian.
}

비트 피들 링은 더 빠를 수 있지만,이 방법은 간단하고 간단하며 혼란 스러울 수 없습니다.


답변

이 기사를 참조 하십시오 :

다음은 컴퓨터 유형을 확인하는 코드입니다.

int num = 1;
if(*(char *)&num == 1)
{
    printf("\nLittle-Endian\n");
}
else
{
    printf("Big-Endian\n");
}

답변

std::endianGCC 8+ 또는 Clang 7+와 같은 C ++ 20 컴파일러에 액세스 할 수있는 경우 사용할 수 있습니다 .

참고 : 2019 년 쾰른 회의에서 std::endian시작 <type_traits>되었지만 이전 되었습니다 <bit>. GCC 8, Clang 7, 8 및 9에 포함되어 <type_traits>있고 GCC 9+ 및 Clang 10+에 포함되어 <bit>있습니다.

#include <bit>

if constexpr (std::endian::native == std::endian::big)
{
    // Big endian system
}
else if constexpr (std::endian::native == std::endian::little)
{
    // Little endian system
}
else
{
    // Something else
}


답변

이것은 일반적으로 컴파일러에서 사용 가능한 헤더 파일을 사용하여 컴파일 타임에 (특히 성능상의 이유로) 수행되거나 사용자가 직접 생성합니다. 리눅스에는 “/usr/include/endian.h”헤더 파일이 있습니다


답변

전처리 기가 기본적으로 정의하는 매크로에 대해 언급 한 사람이 아무도 없습니다. 플랫폼에 따라 다르지만 그들은 자신의 엔디 언 체크를 작성하는 것보다 훨씬 깨끗합니다.

예를 들어; GCC가 정의한 내장 매크로 (X86-64 컴퓨터에서)를 보면 :

:| gcc -dM -E -x c - |grep -i endian
#define __LITTLE_ENDIAN__ 1

PPC 기계에서 나는 얻는다 :

:| gcc -dM -E -x c - |grep -i endian
#define __BIG_ENDIAN__ 1
#define _BIG_ENDIAN 1

( :| gcc -dM -E -x c -매직은 모든 ​​내장 매크로를 인쇄합니다).


답변

흠 … 컴파일러가 단순히 테스트를 최적화하고 고정 된 결과를 반환 값으로 넣을 것이라는 것을 아무도 모른다는 것이 놀랍습니다. 이것은 위의 모든 코드 예제를 효과적으로 쓸모 없게 만듭니다. 반환되는 유일한 것은 컴파일 타임의 엔디안입니다! 그리고 예, 위의 모든 예제를 테스트했습니다. 다음은 MSVC 9.0 (Visual Studio 2008)의 예입니다.

순수한 C 코드

int32 DNA_GetEndianness(void)
{
    union
    {
        uint8  c[4];
        uint32 i;
    } u;

    u.i = 0x01020304;

    if (0x04 == u.c[0])
        return DNA_ENDIAN_LITTLE;
    else if (0x01 == u.c[0])
        return DNA_ENDIAN_BIG;
    else
        return DNA_ENDIAN_UNKNOWN;
}

분해

PUBLIC  _DNA_GetEndianness
; Function compile flags: /Ogtpy
; File c:\development\dna\source\libraries\dna\endian.c
;   COMDAT _DNA_GetEndianness
_TEXT   SEGMENT
_DNA_GetEndianness PROC                 ; COMDAT

; 11   :     union
; 12   :     {
; 13   :         uint8  c[4];
; 14   :         uint32 i;
; 15   :     } u;
; 16   :
; 17   :     u.i = 1;
; 18   :
; 19   :     if (1 == u.c[0])
; 20   :         return DNA_ENDIAN_LITTLE;

    mov eax, 1

; 21   :     else if (1 == u.c[3])
; 22   :         return DNA_ENDIAN_BIG;
; 23   :     else
; 24   :        return DNA_ENDIAN_UNKNOWN;
; 25   : }

    ret
_DNA_GetEndianness ENDP
END

아마도이 기능에 대해서만 컴파일 타임 최적화를 해제 할 수는 있지만 모르겠습니다. 그렇지 않으면 이식 가능하지는 않지만 어셈블리에서 하드 코딩 할 수 있습니다. 그리고 심지어 그조차도 최적화 될 수 있습니다. 정말 어리석은 어셈블러가 필요하고 기존의 모든 CPU / 명령어 세트에 대해 동일한 코드를 구현한다고 생각합니다.

또한, 누군가는 런타임 동안 엔디안이 변경되지 않는다고 말했습니다. 잘못된. 바이 엔디안 머신이 있습니다. 그들의 엔디안은 실행 시간에 따라 달라질 수 있습니다. 또한 리틀 엔디안과 빅 엔디안뿐만 아니라 다른 엔디안도 있습니다 (단어).

나는 동시에 코딩을 싫어하고 좋아합니다 …