νƒœκ·Έ 보관물: endianness

endianness

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()μžˆμŠ΅λ‹ˆλ‹€. λ‹€λ₯Έ ν”Œλž«νΌμ—μ„œλ„ λΉ„μŠ·ν•΄μ•Όν•˜μ§€λ§Œ ν”Œλž«νΌμ΄ 무엇인지 μ•Œμ§€ λͺ»ν•©λ‹ˆλ‹€.


이 글은 C++ μΉ΄ν…Œκ³ λ¦¬μ— λΆ„λ₯˜λ˜μ—ˆκ³  , νƒœκ·Έκ°€ 있으며 λ‹˜μ— μ˜ν•΄ 에 μž‘μ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€.