How do I convert between big-endian and little-endian values in C++?

前端 未结 30 2534
难免孤独
难免孤独 2020-11-21 23:18

How do I convert between big-endian and little-endian values in C++?

EDIT: For clarity, I have to translate binary data (double-precision floating point values and 3

相关标签:
30条回答
  • 2020-11-21 23:56

    Wow, I couldn't believe some of the answers I've read here. There's actually an instruction in assembly which does this faster than anything else. bswap. You could simply write a function like this...

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

    It is MUCH faster than the intrinsics that have been suggested. I've disassembled them and looked. The above function has no prologue/epilogue so virtually has no overhead at all.

    unsigned long _byteswap_ulong(unsigned long value);
    

    Doing 16 bit is just as easy, with the exception that you'd use xchg al, ah. bswap only works on 32-bit registers.

    64-bit is a little more tricky, but not overly so. Much better than all of the above examples with loops and templates etc.

    There are some caveats here... Firstly bswap is only available on 80x486 CPU's and above. Is anyone planning on running it on a 386?!? If so, you can still replace bswap with...

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

    Also inline assembly is only available in x86 code in Visual Studio. A naked function cannot be lined and also isn't available in x64 builds. I that instance, you're going to have to use the compiler intrinsics.

    0 讨论(0)
  • 2020-11-21 23:57

    I have this code that allow me to convert from HOST_ENDIAN_ORDER (whatever it is) to LITTLE_ENDIAN_ORDER or BIG_ENDIAN_ORDER. I use a template, so if I try to convert from HOST_ENDIAN_ORDER to LITTLE_ENDIAN_ORDER and they happen to be the same for the machine for wich I compile, no code will be generated.

    Here is the code with some comments:

    // 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);
    }
    
    0 讨论(0)
  • 2020-11-21 23:57

    I am really surprised no one mentioned htobeXX and betohXX functions. They are defined in endian.h and are very similar to network functions htonXX.

    0 讨论(0)
  • 2020-11-21 23:57

    If you have C++ 17 then add this header

    #include <algorithm>
    

    Use this template function to swap the bytes:

    template <typename T>
    void swapEndian(T& buffer)
    {
        static_assert(std::is_pod<T>::value, "swapEndian support POD type only");
        char* startIndex = static_cast<char*>((void*)buffer.data());
        char* endIndex = startIndex + sizeof(buffer);
        std::reverse(startIndex, endIndex);
    }
    

    call it like:

    swapEndian (stlContainer);
    
    0 讨论(0)
  • 2020-11-21 23:58

    The procedure for going from big-endian to little-endian is the same as going from little-endian to big-endian.

    Here's some example code:

    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);
    }
    
    0 讨论(0)
  • 2020-11-21 23:58

    Here is a basic function to swap to/from little and big endian. It's basic but it doesn't require supplementary libraries.

    void endianness_swap(uint32_t& val) {
        uint8_t a, b, c;
        a = (val & 0xFF000000) >> 24;
        b = (val & 0x00FF0000) >> 16;
        c = (val & 0x0000FF00) >> 8;
        val=(val & 0x000000FF) << 24;
        val = val + (c << 16) + (b << 8) + (a);
    }
    
    0 讨论(0)
提交回复
热议问题