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

前端 未结 30 2530
难免孤独
难免孤独 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:55

    I took a few suggestions from this post and put them together to form this:

    #include 
    #include 
    #include 
    #include 
    #include 
    
    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
    struct swap_bytes
    {
        inline T operator()(T val)
        {
            throw std::out_of_range("data size");
        }
    };
    
    template
    struct swap_bytes
    {
        inline T operator()(T val)
        {
            return val;
        }
    };
    
    template
    struct swap_bytes
    {
        inline T operator()(T val)
        {
            return ((((val) >> 8) & 0xff) | (((val) & 0xff) << 8));
        }
    };
    
    template
    struct swap_bytes
    {
        inline T operator()(T val)
        {
            return ((((val) & 0xff000000) >> 24) |
                    (((val) & 0x00ff0000) >>  8) |
                    (((val) & 0x0000ff00) <<  8) |
                    (((val) & 0x000000ff) << 24));
        }
    };
    
    template<>
    struct swap_bytes
    {
        inline float operator()(float val)
        {
            uint32_t mem =swap_bytes()(*(uint32_t*)&val);
            return *(float*)&mem;
        }
    };
    
    template
    struct swap_bytes
    {
        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
    {
        inline double operator()(double val)
        {
            uint64_t mem =swap_bytes()(*(uint64_t*)&val);
            return *(double*)&mem;
        }
    };
    
    template
    struct do_byte_swap
    {
        inline T operator()(T value)
        {
            return swap_bytes()(value);
        }
    };
    // specialisations when attempting to swap to the same endianess
    template struct do_byte_swap { inline T operator()(T value) { return value; } };
    template struct do_byte_swap { inline T operator()(T value) { return value; } };
    
    } // namespace detail
    
    template
    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::value);
    
        return detail::do_byte_swap()(value);
    }
    

    You would then use it as follows:

    // swaps val from host-byte-order to network-byte-order
    auto swapped = byte_swap(val);
    

    and vice-versa

    // swap a value received from the network into host-byte-order
    auto val = byte_swap(val_from_network);
    

提交回复
热议问题