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