Skip to content

Instantly share code, notes, and snippets.

@martinmoene
Last active June 7, 2019 08:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martinmoene/b48e93fc5ed8030af0017b2e2e7ba152 to your computer and use it in GitHub Desktop.
Save martinmoene/b48e93fc5ed8030af0017b2e2e7ba152 to your computer and use it in GitHub Desktop.
Converting endianness (C++11) - inspired by https://github.com/MayaPosch/ByteBauble
#include "nonstd/endian.hpp"
#include <iostream>
#define print_to_big_endian(x) \
std::cout << #x << ": " << std::hex << to_num(x) << " to be: " << to_num(nonstd::to_big_endian(x)) << "\n"
#define print_to_little_endian(x) \
std::cout << #x << ": " << std::hex << to_num(x) << " to le: " << to_num(nonstd::to_little_endian(x)) << "\n"
#define print_to_native_endian(x) \
std::cout << #x << ": " << std::hex << to_num(x) << " to na: " << to_num(nonstd::to_native_endian(x)) << "\n"
template< typename T >
inline std::uint64_t to_num( T v )
{
return static_cast<std::uint64_t>( v );
}
int main()
{
std::uint8_t x1{ 0x12 };
std::uint16_t x2{ 0x1234 };
std::uint32_t x4{ 0x12345678 };
std::uint64_t x8{ 0x1234567890abcdef };
print_to_big_endian( x1 );
print_to_little_endian( x1 );
print_to_native_endian( x1 ) << "\n";
print_to_big_endian( x2 );
print_to_little_endian( x2 );
print_to_native_endian( x2 ) << "\n";
print_to_big_endian( x4 );
print_to_little_endian( x4 );
print_to_native_endian( x4 ) << "\n";
print_to_big_endian( x8 );
print_to_little_endian( x8 );
print_to_native_endian( x8 ) << "\n";
unsigned char uc{ 0x12 };
unsigned short us{ 0x1234 };
unsigned int ui{ 0x12345678 };
unsigned long ul{ 0x12345678 };
unsigned long long ull{ 0x1234567890abcdef };
print_to_big_endian( uc );
print_to_little_endian( uc );
print_to_native_endian( uc ) << "\n";
print_to_big_endian( us );
print_to_little_endian( us );
print_to_native_endian( us ) << "\n";
print_to_big_endian( ui );
print_to_little_endian( ui );
print_to_native_endian( ui ) << "\n";
print_to_big_endian( ul );
print_to_little_endian( ul );
print_to_native_endian( ul ) << "\n";
print_to_big_endian( ull );
print_to_little_endian( ull );
print_to_native_endian( ull ) << "\n";
}
// cl -EHsc -I../include/ main.cpp && main.exe
// g++ -std=c++11 -I../include/ -o main.exe main.cpp && main.exe
#ifndef nonstd_ENDIAN_HPP
#define nonstd_ENDIAN_HPP
#include <climits>
#include <cstdint>
#include <type_traits>
#ifdef _MSC_VER
# define endian_COMPILER_IS_MSVC 1
# define endian_byteswap16 _byteswap_ushort
# define endian_byteswap32 _byteswap_ulong
# define endian_byteswap64 _byteswap_uint64
#else
# define endian_COMPILER_IS_MSVC 0
# define endian_byteswap16 __builtin_bswap16
# define endian_byteswap32 __builtin_bswap32
# define endian_byteswap64 __builtin_bswap64
#endif
namespace nonstd { namespace endians {
namespace std20 {
// C++20 std::endian:
enum class endian
{
#ifdef _WIN32
little = 0,
big = 1,
native = little
#else
little = __ORDER_LITTLE_ENDIAN__,
big = __ORDER_BIG_ENDIAN__,
native = __BYTE_ORDER__
#endif
};
} // namespace std20
// endianness selection types:
using is_be = std::integral_constant<int, static_cast<int>(std20::endian::big)>;
using is_le = std::integral_constant<int, static_cast<int>(std20::endian::little)>;
using native = std::integral_constant<int, static_cast<int>(std20::endian::native)>;
// make sure all unsigned types are covered, see
// http://ithare.com/c-on-using-int_t-as-overload-and-template-parameters/
template< size_t N > struct uint_by_size;
template<> struct uint_by_size< 8> { using type = std::uint8_t; };
template<> struct uint_by_size<16> { using type = std::uint16_t; };
template<> struct uint_by_size<32> { using type = std::uint32_t; };
template<> struct uint_by_size<64> { using type = std::uint64_t; };
template< typename T >
struct normalized_uint_type
{
static_assert( std::is_integral<T>::value, "");
using type = typename uint_by_size< CHAR_BIT * sizeof( T ) >::type;
static_assert( sizeof( type ) == sizeof( T ), "");
static_assert( std::is_unsigned<type>::value, "");
};
// to big endian (implementation):
inline uint8_t to_big_endian_( uint8_t v, is_le )
{
return v;
}
inline uint16_t to_big_endian_( uint16_t v, is_le )
{
return endian_byteswap16( v );
}
inline uint32_t to_big_endian_( uint32_t v, is_le )
{
return endian_byteswap32( v );
}
inline uint64_t to_big_endian_( uint64_t v, is_le )
{
return endian_byteswap64( v );
}
template< typename T >
inline T to_big_endian_( T v, is_be )
{
return v;
}
// to little endian (implementation):
inline uint8_t to_little_endian_( uint8_t v, is_be )
{
return v;
}
inline uint16_t to_little_endian_( uint16_t v, is_be )
{
return endian_byteswap16( v );
}
inline uint32_t to_little_endian_( uint32_t v, is_be )
{
return endian_byteswap32( v );
}
inline uint64_t to_little_endian_( uint64_t v, is_be )
{
return endian_byteswap64( v );
}
template< typename T >
inline T to_little_endian_( T v, is_le )
{
return v;
}
// to big endian:
template< typename T >
inline T to_big_endian( T v )
{
return to_big_endian_( static_cast< typename normalized_uint_type<T>::type >( v ), native{} );
}
// to little endian:
template< typename T >
inline T to_little_endian( T v )
{
return to_little_endian_( static_cast< typename normalized_uint_type<T>::type >( v ), native{} );
}
// to native endian (identity):
template< typename T >
inline T to_native_endian( T v )
{
return v;
}
} // namespace endians
using endians::to_big_endian;
using endians::to_little_endian;
using endians::to_native_endian;
} // namespace nonstd
#endif
@martinmoene
Copy link
Author

martinmoene commented Jun 4, 2019

Output on Windows:

x1: 12 to be: 12
x1: 12 to le: 12
x1: 12 to na: 12

x2: 1234 to be: 3412
x2: 1234 to le: 1234
x2: 1234 to na: 1234

x4: 12345678 to be: 78563412
x4: 12345678 to le: 12345678
x4: 12345678 to na: 12345678

x8: 1234567890abcdef to be: efcdab9078563412
x8: 1234567890abcdef to le: 1234567890abcdef
x8: 1234567890abcdef to na: 1234567890abcdef

uc: 12 to be: 12
uc: 12 to le: 12
uc: 12 to na: 12

us: 1234 to be: 3412
us: 1234 to le: 1234
us: 1234 to na: 1234

ui: 12345678 to be: 78563412
ui: 12345678 to le: 12345678
ui: 12345678 to na: 12345678

ul: 12345678 to be: 78563412
ul: 12345678 to le: 12345678
ul: 12345678 to na: 12345678

ull: 1234567890abcdef to be: efcdab9078563412
ull: 1234567890abcdef to le: 1234567890abcdef
ull: 1234567890abcdef to na: 1234567890abcdef

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment