나는 어떻게 변환하는 간-endian and little-endian 값에서는 C++?

StackOverflow https://stackoverflow.com/questions/105252

  •  01-07-2019
  •  | 
  •  

문제

나는 어떻게 변환하는 간-endian and little-endian 값에서는 C++?

편집:명확성을 위해,나를 번역하는 이진 데이터(두 번 정밀 부동 소수점 값 및 32 비트와 64 비트 정수)에서 하나의 CPU 공합니다.이는 포함하지 않는 네트워킹,그래서 ntoh()및 이와 유사한 기능이 작동하지 않습니다 여기에.

편집#2:응답 내가 허용에 직접 적용되는 컴파일러에 나는 타겟팅(는 이유는 내가 그것을 선택).그러나,다른 아주 좋은,더 휴대용 대답니다 여기에.

도움이 되었습니까?

해결책

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

는 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 비트 숫자(chars)이 필요하지 않습니다.

또한 이들은 단지 정의를 위한 부호 없는 값들은 작업에 대한 서명된 정수 뿐만 아니라.

에 대한 수레와 복식은 그것의 더 어려운로 일반 정수으로 이러한할 수 있는지에 있을 수 있습니다 호스트 컴퓨터 바이트다.을 얻을 수 있습 little-endian 에 떠-endian 기계와 그 반대입니다.

다른 컴파일러가 내장 유사한뿐만 아니라.

GCC 예를 들어,당신은 직접 전화:

int32_t __builtin_bswap32 (int32_t x)
int64_t __builtin_bswap64 (int64_t x)

(필요없는 무언가를 포함).Afaik 비트입니다.서 선언하고 동일한 기능에서 비 gcc 중심의 방법뿐만 아니라.

16 비트 스왑 그것은 단지는 비트가 회전합니다.

를 호출하면 내장 대신 롤링의 자신의 최상의 성능을 제공합니다 및 코드 밀도 btw..

다른 팁

단순히 넣어:

#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).

바이트 순서 착오 롭 Pyke:

말하자 데이터 스트림에는 리틀-엔디안 로 인코딩된 32 비트의 정수입니다.여기 추출하는 방법(가정 부호 없는 바이트):

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

는 경우-endian 하는 방법은 다음과 같이 추출 그것:

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

TL;박사: 에 대해 걱정하지 마십시오 플랫폼을 기본기 위해,모든 수은 바이트의 스트림에서 읽고,당신은 더 나은 그것을 희망의 정의됩니다.

참고:그것은 주목에서는 주석이 없는 명시적 유형을 변환하는 것이 중요했는 data 할 배열 unsigned charuint8_t.용 signed charchar (만약에의 서명)결과 data[x] 로 승진하는 정수 data[x] << 24 잠재적으로 변화 1 으로 표시 비트는 UB.

하는 경우 이에 대한 목적의 네트워크/호스트의 호환성을 사용해야 한다:

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);
}

가 있음이라는 BSWAP 수행하는 스왑을 위해,당신 매우 빠르.에 대해 읽을 수 있습니다 그것은 .

Visual Studio,또는 더 정확하게 Visual C++런타임 라이브러리에는 플랫폼에 내장이라 _byteswap_ushort(), _byteswap_ulong(), and _byteswap_int64().유해 존재하는 다른 플랫폼에 대한,하지만 나는 무엇을 알고 그들이 부름을 받았습니다.

절차에 대해서가-endian 을 little-endian 와 같은 거에서 little-endian big-endian.

여기에 몇 가지 예를 들어 코드:

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);
}

우리가 이와 함께 템플릿이 있습니다.할 수 있도록 무언가 이것을 좋아한다:

// Specialization for 2-byte types.
template<>
inline void endian_byte_swapper< 2 >(char* dest, char const* src)
{
    // Use bit manipulations instead of accessing individual bytes from memory, much faster.
    ushort* p_dest = reinterpret_cast< ushort* >(dest);
    ushort const* const p_src = reinterpret_cast< ushort const* >(src);
    *p_dest = (*p_src >> 8) | (*p_src << 8);
}

// Specialization for 4-byte types.
template<>
inline void endian_byte_swapper< 4 >(char* dest, char const* src)
{
    // Use bit manipulations instead of accessing individual bytes from memory, much faster.
    uint* p_dest = reinterpret_cast< uint* >(dest);
    uint const* const p_src = reinterpret_cast< uint const* >(src);
    *p_dest = (*p_src >> 24) | ((*p_src & 0x00ff0000) >> 8) | ((*p_src & 0x0000ff00) << 8) | (*p_src << 24);
}

만약 당신이 이렇게 간에 데이터를 전송하는 다른 플랫폼에서 보 ntoh 및 hton 능합니다.

동일한 방법은 당신이에서 C:

short big = 0xdead;
short little = (((big & 0xff)<<8) | ((big & 0xff00)>>8));

수도를 선언하는 벡터의 서명이 없는 문자,memcpy 를 입력 값으로 그것을 반대로 바이트로의 또 다른 벡터와 memcpy 를 바이트를,하지만 하는 것을 주문 크기보다 더 비트-만지작으로 특히 64 비트 값이 있습니다.

에서 가장 POSIX 시스템(을 통해 그것에 POSIX 표준)에 있 endian.에서,사용될 수 있는 무엇인지 결정 인코딩 시스템을 사용합니다.거기에서 그것은 무언가 이것을 좋아한다:

unsigned int change_endian(unsinged int x)
{
    unsigned char *ptr = (unsigned char *)&x;
    return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
}

이 스왑 order(에서 큰-endian 작은 endian):

이 있는 경우 번호를 0xDEADBEEF(에 조금 endian 시스템으로 저장되 0xEFBEADDE),ptr[0]될 것입니다 0xEF,ptr[1]0xBE,etc.

하지만 경우에 당신은 그것을 사용하려 네트워킹,다음 htons,htonl 및 htonll(그리고 그들의 역 ntohs,ntohl 및 ntohll)될 것이 도움을에서 변환하는 호스트하기 위해 네트워크 순서입니다.

참고로,적어도 Windows,htonl()은 보다 훨씬 느리게 자신의 본질적인 대응 _byteswap_ulong().전 DLL 라이브러리 호출로 ws2_32.dll 고,후자는 하나 BSWAP 어셈블리는 명령입니다.따라서 쓰는 경우에는 어떤 플랫폼에 따라 다른 코드를 사용하여 선호 내장을 위해 속도:

#define htonl(x) _byteswap_ulong(x)

이 될 수있다 특히 중요합니다.PNG 이미지 처리는 모두 정수에 저장됩 Big Endian 설명과 함께"하나를 사용할 수 있습 htonl()..."{를 느리게 전형적인 윈도우 프로그램,가 준비되어 있지 않다면}.

대부분의 플랫폼 수 있는 시스템 헤더 파일에 제공하는 효율적인 byteswap 능합니다.리눅스에서 그것은에 <endian.h>.할 수 있는 포장 잘 C++에서:

#include <iostream>

#include <endian.h>

template<size_t N> struct SizeT {};

#define BYTESWAPS(bits) \
template<class T> inline T htobe(T t, SizeT<bits / 8>) { return htobe ## bits(t); } \
template<class T> inline T htole(T t, SizeT<bits / 8>) { return htole ## bits(t); } \
template<class T> inline T betoh(T t, SizeT<bits / 8>) { return be ## bits ## toh(t); } \
template<class T> inline T letoh(T t, SizeT<bits / 8>) { return le ## bits ## toh(t); }

BYTESWAPS(16)
BYTESWAPS(32)
BYTESWAPS(64)

#undef BYTESWAPS

template<class T> inline T htobe(T t) { return htobe(t, SizeT<sizeof t>()); }
template<class T> inline T htole(T t) { return htole(t, SizeT<sizeof t>()); }
template<class T> inline T betoh(T t) { return betoh(t, SizeT<sizeof t>()); }
template<class T> inline T letoh(T t) { return letoh(t, SizeT<sizeof t>()); }

int main()
{
    std::cout << std::hex;
    std::cout << htobe(static_cast<unsigned short>(0xfeca)) << '\n';
    std::cout << htobe(0xafbeadde) << '\n';

    // Use ULL suffix to specify integer constant as unsigned long long 
    std::cout << htobe(0xfecaefbeafdeedfeULL) << '\n';
}

출력:

cafe
deadbeaf
feeddeafbeefcafe

나는 다음과 같이 하나,그냥한 스타일:-)

long swap(long i) {
    char *c = (char *) &i;
    return * (long *) (char[]) {c[3], c[2], c[1], c[0] };
}

심각하게...는 이유를 이해하지 않는 모든 솔루션 복잡한! 는 방법에 대해 가장 간단한,가장 일반적인 템플릿 함수는 스왑을 모든 유형의 어떤 크기의 어떤 상황에서 어떤 운영 체제????

template <typename T>
void SwapEnd(T& var)
{
    char* varArray = reinterpret_cast<char*>(&var);
    for(long i = 0; i < static_cast<long>(sizeof(var)/2); i++)
        std::swap(varArray[sizeof(var) - 1 - i],varArray[i]);
}

그것은 마력의 C 및 C++함께!단순히 스왑 원본 변수는 문자에 의해 문자입니다.

을 기억하지 않았다는 것을 사용하여 간단한 할당 운영자"="기 때문에 일부 개체를 수정될 때 엔디안은 대칭과 복사본을 생성자(또는 할당 운영자)가 작동하지 않습니다.따라서,그것은 더 많은 신뢰할 수 있는 그들을 복사 char 의 char.

전화를 사용하여,

double x = 5;
SwapEnd(x);

지금 x 은 다른 에서 엔디안.

이 코드를 허용하는 나에게로 변환하 HOST_ENDIAN_ORDER(그것이 무엇이든)에 LITTLE_ENDIAN_ORDER 또는 BIG_ENDIAN_ORDER.내 템플릿을 사용하는 경우,그래서 그 시로 변환하 HOST_ENDIAN_ORDER 을 LITTLE_ENDIAN_ORDER 고 그들이 일어날 것에 대해 동일한 기계에 대한 어떤 나는 컴파일,코드가 생성됩니다.

여기에는 코드는 일부 의견:

// We define some constant for little, big and host endianess. Here I use 
// BOOST_LITTLE_ENDIAN/BOOST_BIG_ENDIAN to check the host indianess. If you
// don't want to use boost you will have to modify this part a bit.
enum EEndian
{
  LITTLE_ENDIAN_ORDER,
  BIG_ENDIAN_ORDER,
#if defined(BOOST_LITTLE_ENDIAN)
  HOST_ENDIAN_ORDER = LITTLE_ENDIAN_ORDER
#elif defined(BOOST_BIG_ENDIAN)
  HOST_ENDIAN_ORDER = BIG_ENDIAN_ORDER
#else
#error "Impossible de determiner l'indianness du systeme cible."
#endif
};

// this function swap the bytes of values given it's size as a template
// parameter (could sizeof be used?).
template <class T, unsigned int size>
inline T SwapBytes(T value)
{
  union
  {
     T value;
     char bytes[size];
  } in, out;

  in.value = value;

  for (unsigned int i = 0; i < size / 2; ++i)
  {
     out.bytes[i] = in.bytes[size - 1 - i];
     out.bytes[size - 1 - i] = in.bytes[i];
  }

  return out.value;
}

// Here is the function you will use. Again there is two compile-time assertion
// that use the boost librarie. You could probably comment them out, but if you
// do be cautious not to use this function for anything else than integers
// types. This function need to be calles like this :
//
//     int x = someValue;
//     int i = EndianSwapBytes<HOST_ENDIAN_ORDER, BIG_ENDIAN_ORDER>(x);
//
template<EEndian from, EEndian to, class T>
inline T EndianSwapBytes(T value)
{
  // A : La donnée à swapper à une taille de 2, 4 ou 8 octets
  BOOST_STATIC_ASSERT(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);

  // A : La donnée à swapper est d'un type arithmetic
  BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value);

  // Si from et to sont du même type on ne swap pas.
  if (from == to)
     return value;

  return SwapBytes<T, sizeof(T)>(value);
}

는 경우-endian32-bit unsigned integer 같 0xAABBCCDD 은 다음과 같이 계산됩니다 2864434397,다음 같은 32-bit unsigned integer 같 0xDDCCBBAA 에 little-endian 프로세서는 또한 동등하 2864434397.

는 경우-endian16-bit unsigned short 같 0xAABB 은 다음과 같이 계산됩니다 43707,다음 동일한 16-bit unsigned short 같 0xBBAA 에 little-endian 프로세서는 또한 동등하 43707.

여기에 몇 가지 편리하는 기능을 교환하는 바이트에서 little-endian big-endian 고 그 반대의 경우-->

// can be used for short, unsigned short, word, unsigned word (2-byte types)
#define BYTESWAP16(n) (((n&0xFF00)>>8)|((n&0x00FF)<<8))

// can be used for int or unsigned int or float (4-byte types)
#define BYTESWAP32(n) ((BYTESWAP16((n&0xFFFF0000)>>16))|((BYTESWAP16(n&0x0000FFFF))<<16))

// can be used for unsigned long long or double (8-byte types)
#define BYTESWAP64(n) ((BYTESWAP32((n&0xFFFFFFFF00000000)>>32))|((BYTESWAP32(n&0x00000000FFFFFFFF))<<32))

여기에 일반화된 버전이 나온 상단의 머리를 교환하는 값에는 장소입니다.다른 제안이 더 나은 것을 경우 성능이 문제입니다.

 template<typename T>
    void ByteSwap(T * p)
    {
        for (int i = 0;  i < sizeof(T)/2;  ++i)
            std::swap(((char *)p)[i], ((char *)p)[sizeof(T)-1-i]);
    }

면책 조항: 내가 시도하지 않은 컴파일이나 테스트됩니다.

이 걸릴 경우의 일반적인 패턴을 반대의 순서를 비는 단어,그리고 발췌하는 부분을 반대로 조금 내에서 각각의 바이트를,당신은 왼쪽으로는 뭔가만을 반대 바이트에는 단어입니다.64 비트:

x = ((x & 0x00000000ffffffff) << 32) ^ ((x >> 32) & 0x00000000ffffffff);
x = ((x & 0x0000ffff0000ffff) << 16) ^ ((x >> 16) & 0x0000ffff0000ffff);
x = ((x & 0x00ff00ff00ff00ff) <<  8) ^ ((x >>  8) & 0x00ff00ff00ff00ff);

컴파일러 청소 불필요한 비트가 마스킹 작업(왼쪽에서 그들을 강조하는 패턴),지만 그렇지 않은 경우,당신은 다시 작성할 수 있습니다 첫 번째 줄이는 방법:

x = ( x                       << 32) ^  (x >> 32);

해야 하는 일반적으로 단순화하는 단일 회전 교육에서 가장 아키텍처(을 무시하고는 전체 작업은 아마도 하나의 명령).

에 RISC 프로세서는 대형,복잡한 상수를 일으킬 수 있는 컴파일러 어려움이 있습니다.할 수 있는 사소 계산 각각의 상수 이전에서 하나,하지만.그래서 다음과 같:

uint64_t k = 0x00000000ffffffff; /* compiler should know a trick for this */
x = ((x & k) << 32) ^ ((x >> 32) & k);
k ^= k << 16;
x = ((x & k) << 16) ^ ((x >> 16) & k);
k ^= k << 8;
x = ((x & k) <<  8) ^ ((x >>  8) & k);

당신이 좋아하는 경우에,당신은 쓸 수는 있습니다.지 않을 것이 효율적이지만,그냥 재미를위한:

int i = sizeof(x) * CHAR_BIT / 2;
uintmax_t k = (1 << i) - 1;
while (i >= 8)
{
    x = ((x & k) << i) ^ ((x >> i) & k);
    i >>= 1;
    k ^= k << i;
}

과 완전성을 위해,여기에의 간이 32 비트 버전의 첫번째 형태:

x = ( x               << 16) ^  (x >> 16);
x = ((x & 0x00ff00ff) <<  8) ^ ((x >>  8) & 0x00ff00ff);

다만 생각을 내가 내 자신의 솔루션이기 때문에 나는 보지 못했습니다.그것은 작은 휴대용 C++템플릿의 기능과 휴대용 단지 사용 비트 작업입니다.

template<typename T> inline static T swapByteOrder(const T& val) {
    int totalBytes = sizeof(val);
    T swapped = (T) 0;
    for (int i = 0; i < totalBytes; ++i) {
        swapped |= (val >> (8*(totalBytes-i-1)) & 0xFF) << (8*i);
    }
    return swapped;
}

으로 아래 주어진 코드 간에 교환할 수 있습 BigEndian 고 쉽게 LittleEndian

#define uint32_t unsigned 
#define uint16_t unsigned short

#define swap16(x) ((((uint16_t)(x) & 0x00ff)<<8)| \
(((uint16_t)(x) & 0xff00)>>8))

#define swap32(x) ((((uint32_t)(x) & 0x000000ff)<<24)| \
(((uint32_t)(x) & 0x0000ff00)<<8)| \
(((uint32_t)(x) & 0x00ff0000)>>8)| \
(((uint32_t)(x) & 0xff000000)>>24))

나는 정말 놀라게 아무도 없 htobeXX 및 betohXX 능합니다.에 정의된 endian.서와 매우 유사하다는 네트워크 기능을 htonXX.

Wow,믿을 수가 없었 답변 중 일부는 여기에서 읽었.실제로 거기는 지침에 어셈블리는 이보다 더 빨리 다른 것.bswap.간단하게 작성할 수 있습 기능이 다음과 같이...

__declspec(naked) uint32_t EndianSwap(uint32 value)
{
    __asm
    {
        mov eax, dword ptr[esp + 4]
        bswap eax
        ret
    }
}

보다 더 빠르게 내장 된 제안했다.나는 분해 그들을 보였다.위의 기능이 없 프롤로그/에필로그 그래서 거의 없는 오버헤드에서 모두.

unsigned long _byteswap_ulong(unsigned long value);

하 16 비트가 쉽다는 점을 제외하고,다음을 사용할 수 있습니다 xchg al,아입니다.bswap 만 작품에서 32 비트 레지스터가 있습니다.

64-bit 은 조금 더 까다,하지만 지나치게 그래서.보다 훨씬 더 모든 위의 예제와 함께 템플릿 루프 및 등등.

다음과 같은 몇 가지 경고가 있습니다 여기...첫째 bswap 에서만 사용할 수 있 80x486CPU 습니다.는 사람 계획을 실행에 그것에 386?!?그렇다면,당신은 여전히 대체 bswap 으로...

mov ebx, eax
shr ebx, 16
xchg bl, bh
xchg al, ah
shl eax, 16
or eax, ebx

또한 인라인이 어셈블리에서만 사용할 수 있 86Visual Studio 에서 코드.벌 거 벗은 기능을 수 없는 줄도에서 사용할 수 없습니다 x64 있습니다.나는 그를 들어,당신을 사용하는 컴파일러가 내장.

휴대용 기술을 구현하기 위한 최적화-친절한 정렬되지 않은 아닌 내부 endian 줍니다.그들은 작업에 모든 컴파일러,모든 경계를 정렬하고 매 byte ordering.이러한 정렬되지 않은 루틴은 보충하거나,토의에 따라 원어민 endian 및 정렬.는 부분을 나열하지만 당신은 아이디어를 얻을 수 있습니다.BO*은 상수 값에 따라 원어민 byte ordering.

uint32_t sw_get_uint32_1234(pu32)
uint32_1234 *pu32;
{
  union {
    uint32_1234 u32_1234;
    uint32_t u32;
  } bou32;
  bou32.u32_1234[0] = (*pu32)[BO32_0];
  bou32.u32_1234[1] = (*pu32)[BO32_1];
  bou32.u32_1234[2] = (*pu32)[BO32_2];
  bou32.u32_1234[3] = (*pu32)[BO32_3];
  return(bou32.u32);
}

void sw_set_uint32_1234(pu32, u32)
uint32_1234 *pu32;
uint32_t u32;
{
  union {
    uint32_1234 u32_1234;
    uint32_t u32;
  } bou32;
  bou32.u32 = u32;
  (*pu32)[BO32_0] = bou32.u32_1234[0];
  (*pu32)[BO32_1] = bou32.u32_1234[1];
  (*pu32)[BO32_2] = bou32.u32_1234[2];
  (*pu32)[BO32_3] = bou32.u32_1234[3];
}

#if HAS_SW_INT64
int64 sw_get_int64_12345678(pi64)
int64_12345678 *pi64;
{
  union {
    int64_12345678 i64_12345678;
    int64 i64;
  } boi64;
  boi64.i64_12345678[0] = (*pi64)[BO64_0];
  boi64.i64_12345678[1] = (*pi64)[BO64_1];
  boi64.i64_12345678[2] = (*pi64)[BO64_2];
  boi64.i64_12345678[3] = (*pi64)[BO64_3];
  boi64.i64_12345678[4] = (*pi64)[BO64_4];
  boi64.i64_12345678[5] = (*pi64)[BO64_5];
  boi64.i64_12345678[6] = (*pi64)[BO64_6];
  boi64.i64_12345678[7] = (*pi64)[BO64_7];
  return(boi64.i64);
}
#endif

int32_t sw_get_int32_3412(pi32)
int32_3412 *pi32;
{
  union {
    int32_3412 i32_3412;
    int32_t i32;
  } boi32;
  boi32.i32_3412[2] = (*pi32)[BO32_0];
  boi32.i32_3412[3] = (*pi32)[BO32_1];
  boi32.i32_3412[0] = (*pi32)[BO32_2];
  boi32.i32_3412[1] = (*pi32)[BO32_3];
  return(boi32.i32);
}

void sw_set_int32_3412(pi32, i32)
int32_3412 *pi32;
int32_t i32;
{
  union {
    int32_3412 i32_3412;
    int32_t i32;
  } boi32;
  boi32.i32 = i32;
  (*pi32)[BO32_0] = boi32.i32_3412[2];
  (*pi32)[BO32_1] = boi32.i32_3412[3];
  (*pi32)[BO32_2] = boi32.i32_3412[0];
  (*pi32)[BO32_3] = boi32.i32_3412[1];
}

uint32_t sw_get_uint32_3412(pu32)
uint32_3412 *pu32;
{
  union {
    uint32_3412 u32_3412;
    uint32_t u32;
  } bou32;
  bou32.u32_3412[2] = (*pu32)[BO32_0];
  bou32.u32_3412[3] = (*pu32)[BO32_1];
  bou32.u32_3412[0] = (*pu32)[BO32_2];
  bou32.u32_3412[1] = (*pu32)[BO32_3];
  return(bou32.u32);
}

void sw_set_uint32_3412(pu32, u32)
uint32_3412 *pu32;
uint32_t u32;
{
  union {
    uint32_3412 u32_3412;
    uint32_t u32;
  } bou32;
  bou32.u32 = u32;
  (*pu32)[BO32_0] = bou32.u32_3412[2];
  (*pu32)[BO32_1] = bou32.u32_3412[3];
  (*pu32)[BO32_2] = bou32.u32_3412[0];
  (*pu32)[BO32_3] = bou32.u32_3412[1];
}

float sw_get_float_1234(pf)
float_1234 *pf;
{
  union {
    float_1234 f_1234;
    float f;
  } bof;
  bof.f_1234[0] = (*pf)[BO32_0];
  bof.f_1234[1] = (*pf)[BO32_1];
  bof.f_1234[2] = (*pf)[BO32_2];
  bof.f_1234[3] = (*pf)[BO32_3];
  return(bof.f);
}

void sw_set_float_1234(pf, f)
float_1234 *pf;
float f;
{
  union {
    float_1234 f_1234;
    float f;
  } bof;
  bof.f = (float)f;
  (*pf)[BO32_0] = bof.f_1234[0];
  (*pf)[BO32_1] = bof.f_1234[1];
  (*pf)[BO32_2] = bof.f_1234[2];
  (*pf)[BO32_3] = bof.f_1234[3];
}

double sw_get_double_12345678(pd)
double_12345678 *pd;
{
  union {
    double_12345678 d_12345678;
    double d;
  } bod;
  bod.d_12345678[0] = (*pd)[BO64_0];
  bod.d_12345678[1] = (*pd)[BO64_1];
  bod.d_12345678[2] = (*pd)[BO64_2];
  bod.d_12345678[3] = (*pd)[BO64_3];
  bod.d_12345678[4] = (*pd)[BO64_4];
  bod.d_12345678[5] = (*pd)[BO64_5];
  bod.d_12345678[6] = (*pd)[BO64_6];
  bod.d_12345678[7] = (*pd)[BO64_7];
  return(bod.d);
}

void sw_set_double_12345678(pd, d)
double_12345678 *pd;
double d;
{
  union {
    double_12345678 d_12345678;
    double d;
  } bod;
  bod.d = d;
  (*pd)[BO64_0] = bod.d_12345678[0];
  (*pd)[BO64_1] = bod.d_12345678[1];
  (*pd)[BO64_2] = bod.d_12345678[2];
  (*pd)[BO64_3] = bod.d_12345678[3];
  (*pd)[BO64_4] = bod.d_12345678[4];
  (*pd)[BO64_5] = bod.d_12345678[5];
  (*pd)[BO64_6] = bod.d_12345678[6];
  (*pd)[BO64_7] = bod.d_12345678[7];
}

이러한 typedef 의 혜택을 올리는 오류를 컴파일러는 경우에는 사용되지 않습 접근,따라서 완화 잊 접근니다.

typedef char int8_1[1], uint8_1[1];

typedef char int16_12[2], uint16_12[2]; /* little endian */
typedef char int16_21[2], uint16_21[2]; /* big endian */

typedef char int24_321[3], uint24_321[3]; /* Alpha Micro, PDP-11 */

typedef char int32_1234[4], uint32_1234[4]; /* little endian */
typedef char int32_3412[4], uint32_3412[4]; /* Alpha Micro, PDP-11 */
typedef char int32_4321[4], uint32_4321[4]; /* big endian */

typedef char int64_12345678[8], uint64_12345678[8]; /* little endian */
typedef char int64_34128756[8], uint64_34128756[8]; /* Alpha Micro, PDP-11 */
typedef char int64_87654321[8], uint64_87654321[8]; /* big endian */

typedef char float_1234[4]; /* little endian */
typedef char float_3412[4]; /* Alpha Micro, PDP-11 */
typedef char float_4321[4]; /* big endian */

typedef char double_12345678[8]; /* little endian */
typedef char double_78563412[8]; /* Alpha Micro? */
typedef char double_87654321[8]; /* big endian */

나는 최근에 쓴 매크로를 이렇게 C 지만,그것은 동일하게 유효한 C++에서:

#define REVERSE_BYTES(...) do for(size_t REVERSE_BYTES=0; REVERSE_BYTES<sizeof(__VA_ARGS__)>>1; ++REVERSE_BYTES)\
    ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES],\
    ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES],\
    ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES];\
while(0)

그것은 모든 유형과 반대 바이트에서 전달된다.를 들어 사용:

int main(){
    unsigned long long x = 0xABCDEF0123456789;
    printf("Before: %llX\n",x);
    REVERSE_BYTES(x);
    printf("After : %llX\n",x);

    char c[7]="nametag";
    printf("Before: %c%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5],c[6]);
    REVERSE_BYTES(c);
    printf("After : %c%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5],c[6]);
}

는 인쇄:

Before: ABCDEF0123456789
After : 8967452301EFCDAB
Before: nametag
After : gateman

위의 완벽하게 복사/붙여넣기 할 수 있지만,많은 일들이 일어나고 있는데요,여기에 그래서 나는 분이 어떻게 작동 조각으:

첫 번째 주목할 만한 것은 전체 매크로에 넣 do while(0) 니다.이 관용적인 을 허용하는 정상적인 세미콜론 후에 사용됩니다.

다음 사용의 변수 이름 REVERSE_BYTESfor 루프의 카운터입니다.매크로의 이름 자체로 사용되는 변수 이름을 지키지 않는다는 충돌 가진 어떤 다른 기호할 수 있는 범위에서 어디서나 매크로를 사용됩니다.이 이름은 내에서 사용되고 있는 매크로의 확장,그것은지 확장될 때 다시 사용되는 변수로 이름을 여기에.

for 루프가 있는 두 개의 바이트를 참조 및 XOR 교환 (그래서 일시적 변수 이름이 필요하지 않습니다):

((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]

__VA_ARGS__ 을 나타내었다 무엇에 주어진 매크로를 사용하는 유연성을 증가시킬 수 있습니다 무엇의에 통과(불구하지 않습으로 많).소 이 인수의 그리고 캐스팅되는 unsigned char 포인터를 허용하도록 교환의 바이트를 통해 배열 [] subscripting.

최종 독점의 부족 {} 호하는 장치입니다.그들이 필요하지 않기 때문에 모든 단계에서 각각의 스왑 가입 쉼표 통신수, 들을 만들고,하나의 문입니다.

마지막으로,점은 주목할 만한 가치가 있는 이상적인 방법으로 수집 속도가 최우선입니다.이것이 중요한 요소,일부의 유형-특정 매크로 또는 플랫폼-특정 지시어에서 참조하는 다른 답변을 가능성이 있는 더 나은 옵션입니다.이 접근 방식은,그러나,휴대용하는 모든 종류의 모든 주요한 플랫폼으로,C 및 C++언어입니다.

Boost::endian, 고 구현하지 않는다!

링크

여기에는 방법을 읽어 더블에 저장된 IEEE754 64 비트 포맷이 있는 경우에도 당신의 호스트 컴퓨터가 사용하는 다른 시스템입니다.

/*
* read a double from a stream in ieee754 format regardless of host
*  encoding.
*  fp - the stream
*  bigendian - set to if big bytes first, clear for little bytes
*              first
*
*/
double freadieee754(FILE *fp, int bigendian)
{
    unsigned char buff[8];
    int i;
    double fnorm = 0.0;
    unsigned char temp;
    int sign;
    int exponent;
    double bitval;
    int maski, mask;
    int expbits = 11;
    int significandbits = 52;
    int shift;
    double answer;

    /* read the data */
    for (i = 0; i < 8; i++)
        buff[i] = fgetc(fp);
    /* just reverse if not big-endian*/
    if (!bigendian)
    {
        for (i = 0; i < 4; i++)
        {
            temp = buff[i];
            buff[i] = buff[8 - i - 1];
            buff[8 - i - 1] = temp;
        }
    }
    sign = buff[0] & 0x80 ? -1 : 1;
    /* exponet in raw format*/
    exponent = ((buff[0] & 0x7F) << 4) | ((buff[1] & 0xF0) >> 4);

    /* read inthe mantissa. Top bit is 0.5, the successive bits half*/
    bitval = 0.5;
    maski = 1;
    mask = 0x08;
    for (i = 0; i < significandbits; i++)
    {
        if (buff[maski] & mask)
            fnorm += bitval;

        bitval /= 2.0;
        mask >>= 1;
        if (mask == 0)
        {
            mask = 0x80;
            maski++;
        }
    }
    /* handle zero specially */
    if (exponent == 0 && fnorm == 0)
        return 0.0;

    shift = exponent - ((1 << (expbits - 1)) - 1); /* exponent = shift + bias */
    /* nans have exp 1024 and non-zero mantissa */
    if (shift == 1024 && fnorm != 0)
        return sqrt(-1.0);
    /*infinity*/
    if (shift == 1024 && fnorm == 0)
    {

#ifdef INFINITY
        return sign == 1 ? INFINITY : -INFINITY;
#endif
        return  (sign * 1.0) / 0.0;
    }
    if (shift > -1023)
    {
        answer = ldexp(fnorm + 1.0, shift);
        return answer * sign;
    }
    else
    {
        /* denormalised numbers */
        if (fnorm == 0.0)
            return 0.0;
        shift = -1022;
        while (fnorm < 1.0)
        {
            fnorm *= 2;
            shift--;
        }
        answer = ldexp(fnorm, shift);
        return answer * sign;
    }
}

의 나머지 부분에 대한 스위트룸의 기능을 포함하여 작성과 정수 루틴 내 github 프로젝트

https://github.com/MalcolmMcLean/ieee754

바이트로 교환하는 ye olde3 단계-xor 수 피벗 템플릿에서는 기능을 제공합한 유연한,빠른 O(ln2)솔루션이 필요하지 않은 라이브러리 스타일로 여기 또한 거부하는 1 바이트 유형:

template<typename T>void swap(T &t){
    for(uint8_t pivot = 0; pivot < sizeof(t)/2; pivot ++){
        *((uint8_t *)&t + pivot) ^= *((uint8_t *)&t+sizeof(t)-1- pivot);
        *((uint8_t *)&t+sizeof(t)-1- pivot) ^= *((uint8_t *)&t + pivot);
        *((uint8_t *)&t + pivot) ^= *((uint8_t *)&t+sizeof(t)-1- pivot);
    }
}

처럼 보인다 안전한 방법으로 사용하는 것입니다 htons 에서 각각의 단어입니다.그래서,당신이...

std::vector<uint16_t> storage(n);  // where n is the number to be converted

// the following would do the trick
std::transform(word_storage.cbegin(), word_storage.cend()
  , word_storage.begin(), [](const uint16_t input)->uint16_t {
  return htons(input); });

위 것 no-op 는 경우에도 동작 시스템,그래서 내가 찾는 것이 최상의 플랫폼으로 사용하는 컴파일 타임 조건 여부를 결정하 htons is a no-op.그것은 오(n)니다.Mac,무언가가 될 것이다.

#if (__DARWIN_BYTE_ORDER != __DARWIN_BIG_ENDIAN)
std::transform(word_storage.cbegin(), word_storage.cend()
  , word_storage.begin(), [](const uint16_t input)->uint16_t {
  return htons(input); });
#endif

찾아 비트 시프트,로 이것은 기본적으로 당신이해야 할 모든 당신을 스왑터->big endian.다음에 따라 비트 크기를 변경하는 방법 당신이 비트가 변하고 있다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top