Last active
June 7, 2019 08:16
-
-
Save martinmoene/b48e93fc5ed8030af0017b2e2e7ba152 to your computer and use it in GitHub Desktop.
Converting endianness (C++11) - inspired by https://github.com/MayaPosch/ByteBauble
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Output on Windows: