C ++에서 빅 엔디안과 리틀 엔디안 값을 어떻게 변환합니까? 변환해야합니다. 이것은 네트워킹과

C ++에서 빅 엔디안과 리틀 엔디안 값을 어떻게 변환합니까?

편집 : 명확성을 위해 이진 데이터 (배정 밀도 부동 소수점 값 및 32 비트 및 64 비트 정수)를 한 CPU 아키텍처에서 다른 CPU 아키텍처로 변환해야합니다. 이것은 네트워킹과 관련이 없으므로 ntoh () 및 이와 유사한 함수는 여기서 작동하지 않습니다.

편집 # 2 : 내가 받아 들인 대답은 내가 타겟팅하는 컴파일러에 직접 적용됩니다 (그래서 내가 선택한 이유). 그러나 여기에는 매우 훌륭하고 이식성이 좋은 다른 답변이 있습니다.



답변

당신이 사용하는 경우 Visual C ++를 다음을 수행 : 당신은 다음과 같은 기능을 intrin.h 포함 전화 :

16 비트 숫자의 경우 :

unsigned short _byteswap_ushort(unsigned short value);

32 비트 숫자의 경우 :

unsigned long _byteswap_ulong(unsigned long value);

64 비트 숫자의 경우 :

unsigned __int64 _byteswap_uint64(unsigned __int64 value);

8 비트 숫자 (문자)는 변환 할 필요가 없습니다.

또한 이들은 부호없는 정수에 대해서만 작동합니다.

float 및 double의 경우 호스트 시스템에 바이트 순서가 있거나 없을 수 있으므로 일반 정수를 사용하는 것이 더 어렵습니다. 빅 엔디안 머신에서 리틀 엔디안 수레를 얻을 수 있으며 그 반대도 가능합니다.

다른 컴파일러도 비슷한 본질을 가지고 있습니다.

예를 들어 GCC 에서는 여기에 설명 된대로 일부 내장을 직접 호출 할 수 있습니다 .

uint32_t __builtin_bswap32 (uint32_t x)
uint64_t __builtin_bswap64 (uint64_t x)

(무엇을 포함 할 필요가 없습니다). Afaik bits.h는 gcc 중심이 아닌 방식으로 동일한 함수를 선언합니다.

16 비트 스왑은 비트 회전입니다.

롤링 대신 내장 함수를 호출하면 최상의 성능과 코드 밀도를 얻을 수 있습니다.


답변

간단히 말해서:

#include <climits>

template <typename T>
T swap_endian(T u)
{
    static_assert (CHAR_BIT == 8, "CHAR_BIT != 8");

    union
    {
        T u;
        unsigned char u8[sizeof(T)];
    } source, dest;

    source.u = u;

    for (size_t k = 0; k < sizeof(T); k++)
        dest.u8[k] = source.u8[sizeof(T) - k - 1];

    return dest.u;
}

사용법 : swap_endian<uint32_t>(42).


답변

에서 바이트 주문 착오 롭 파이크에 의해 :

데이터 스트림에 리틀 엔디안 인코딩 된 32 비트 정수가 있다고 가정 해 봅시다. 부호없는 바이트를 가정하여 추출하는 방법은 다음과 같습니다.

i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);

빅 엔디안이라면 추출 방법은 다음과 같습니다.

i = (data[3]<<0) | (data[2]<<8) | (data[1]<<16) | (data[0]<<24);

TL; DR : 플랫폼 기본 순서에 대해 걱정하지 마십시오 . 카운트는 모두 읽고있는 스트림의 바이트 순서이며 잘 정의되어 있기를 바랍니다.

참고 : 주석에서 명시 적 유형 변환이없는 것으로 언급되었으므로 또는 data의 배열이어야합니다 . 사용 또는 (서명 경우)가 발생합니다 정수로 승진하고 잠재적 UB이다 부호 비트에 1을 이동.unsigned charuint8_tsigned charchardata[x]data[x] << 24


답변

네트워크 / 호스트 호환성을 위해이 작업을 수행하는 경우 다음을 사용해야합니다.

ntohl() //Network to Host byte order (Long)
htonl() //Host to Network byte order (Long)

ntohs() //Network to Host byte order (Short)
htons() //Host to Network byte order (Short)

다른 이유로이 작업을 수행하는 경우 여기에 제공된 byte_swap 솔루션 중 하나가 제대로 작동합니다.


답변

나는이 게시물에서 몇 가지 제안을하고 이것을 구성하기 위해 함께 모았습니다.

#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
#include <boost/detail/endian.hpp>
#include <stdexcept>

enum endianness
{
    little_endian,
    big_endian,
    network_endian = big_endian,

    #if defined(BOOST_LITTLE_ENDIAN)
        host_endian = little_endian
    #elif defined(BOOST_BIG_ENDIAN)
        host_endian = big_endian
    #else
        #error "unable to determine system endianness"
    #endif
};

namespace detail {

template<typename T, size_t sz>
struct swap_bytes
{
    inline T operator()(T val)
    {
        throw std::out_of_range("data size");
    }
};

template<typename T>
struct swap_bytes<T, 1>
{
    inline T operator()(T val)
    {
        return val;
    }
};

template<typename T>
struct swap_bytes<T, 2>
{
    inline T operator()(T val)
    {
        return ((((val) >> 8) & 0xff) | (((val) & 0xff) << 8));
    }
};

template<typename T>
struct swap_bytes<T, 4>
{
    inline T operator()(T val)
    {
        return ((((val) & 0xff000000) >> 24) |
                (((val) & 0x00ff0000) >>  8) |
                (((val) & 0x0000ff00) <<  8) |
                (((val) & 0x000000ff) << 24));
    }
};

template<>
struct swap_bytes<float, 4>
{
    inline float operator()(float val)
    {
        uint32_t mem =swap_bytes<uint32_t, sizeof(uint32_t)>()(*(uint32_t*)&val);
        return *(float*)&mem;
    }
};

template<typename T>
struct swap_bytes<T, 8>
{
    inline T operator()(T val)
    {
        return ((((val) & 0xff00000000000000ull) >> 56) |
                (((val) & 0x00ff000000000000ull) >> 40) |
                (((val) & 0x0000ff0000000000ull) >> 24) |
                (((val) & 0x000000ff00000000ull) >> 8 ) |
                (((val) & 0x00000000ff000000ull) << 8 ) |
                (((val) & 0x0000000000ff0000ull) << 24) |
                (((val) & 0x000000000000ff00ull) << 40) |
                (((val) & 0x00000000000000ffull) << 56));
    }
};

template<>
struct swap_bytes<double, 8>
{
    inline double operator()(double val)
    {
        uint64_t mem =swap_bytes<uint64_t, sizeof(uint64_t)>()(*(uint64_t*)&val);
        return *(double*)&mem;
    }
};

template<endianness from, endianness to, class T>
struct do_byte_swap
{
    inline T operator()(T value)
    {
        return swap_bytes<T, sizeof(T)>()(value);
    }
};
// specialisations when attempting to swap to the same endianess
template<class T> struct do_byte_swap<little_endian, little_endian, T> { inline T operator()(T value) { return value; } };
template<class T> struct do_byte_swap<big_endian,    big_endian,    T> { inline T operator()(T value) { return value; } };

} // namespace detail

template<endianness from, endianness to, class T>
inline T byte_swap(T value)
{
    // ensure the data is only 1, 2, 4 or 8 bytes
    BOOST_STATIC_ASSERT(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);
    // ensure we're only swapping arithmetic types
    BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value);

    return detail::do_byte_swap<from, to, T>()(value);
}

답변

빅 엔디안에서 리틀 엔디안으로가는 절차는 리틀 엔디안에서 빅 엔디안으로가는 절차와 동일합니다.

예제 코드는 다음과 같습니다.

void swapByteOrder(unsigned short& us)
{
    us = (us >> 8) |
         (us << 8);
}

void swapByteOrder(unsigned int& ui)
{
    ui = (ui >> 24) |
         ((ui<<8) & 0x00FF0000) |
         ((ui>>8) & 0x0000FF00) |
         (ui << 24);
}

void swapByteOrder(unsigned long long& ull)
{
    ull = (ull >> 56) |
          ((ull<<40) & 0x00FF000000000000) |
          ((ull<<24) & 0x0000FF0000000000) |
          ((ull<<8) & 0x000000FF00000000) |
          ((ull>>8) & 0x00000000FF000000) |
          ((ull>>24) & 0x0000000000FF0000) |
          ((ull>>40) & 0x000000000000FF00) |
          (ull << 56);
}

답변

BSWAP라는 조립 명령이 있으며, 스왑을 매우 빠르게 수행 합니다. 여기에서 읽을 수 있습니다 .

Visual Studio 또는보다 정확하게는 Visual C ++ 런타임 라이브러리에는이를위한 플랫폼 내장 기능이 _byteswap_ushort(), _byteswap_ulong(), and _byteswap_int64()있습니다. 다른 플랫폼에서도 비슷해야하지만 플랫폼이 무엇인지 알지 못합니다.