#include #include #include /*************************************************** * Switching byte order * * A 64-bit unsigned integer contains eight bytes. * * Consider the value * * 0x0123456789abcdef. * * Its eight bytes, from most significant to least * significant, are * * 01 23 45 67 89 ab cd ef. * * The numerical value itself does not have an * endianness. Endianness describes the order in * which the bytes of a multi-byte value are stored * in memory. * * * BIG-ENDIAN * * In big-endian byte order, the most significant * byte is stored first, at the lowest memory * address. * * Thus, the bytes appear in memory as * * address: 0 1 2 3 4 5 6 7 * * byte: 01 23 45 67 89 ab cd ef * * * LITTLE-ENDIAN * * In little-endian byte order, the least significant * byte is stored first, at the lowest memory * address. * * The same value therefore appears in memory as * * address: 0 1 2 3 4 5 6 7 * * byte: ef cd ab 89 67 45 23 01 * * * REVERSING THE BYTE ORDER * * When transferring binary data between systems or * interpreting a file or communication protocol, we * may need to reverse the order of the bytes. * * For example, reversing the bytes of * * 0x0123456789abcdef * * gives * * 0xefcdab8967452301. * * We can do this using bit masks and bit shifts. * * * SELECTING ONE BYTE * * The mask * * 0x00000000000000ff * * selects the least significant byte: * * 0x0123456789abcdef * & 0x00000000000000ff * ------------------ * 0x00000000000000ef. * * To move this byte to the most significant * position, shift it 56 bits to the left: * * 0x00000000000000ef << 56 * * giving * * 0xef00000000000000. * * * MOVING ALL EIGHT BYTES * * We repeat this process for each byte: * * byte 0: shift left 56 bits * byte 1: shift left 40 bits * byte 2: shift left 24 bits * byte 3: shift left 8 bits * byte 4: shift right 8 bits * byte 5: shift right 24 bits * byte 6: shift right 40 bits * byte 7: shift right 56 bits. * * Finally, bitwise OR combines the eight shifted * bytes into the result. * * * NOTICE * * Reversing the byte order twice restores the * original value: * * switch_endian( switch_endian( n ) ) == n. ***************************************************/ // Function declarations int main(); std::uint64_t switch_endian( std::uint64_t n ); // Function definitions int main() { std::uint64_t a{ UINT64_C( 0x0123456789abcdef ) }; std::uint64_t b{ UINT64_C( 0xefcdab8967452301 ) }; std::cout << std::hex << std::setfill( '0' ); std::cout << "Original: 0x" << std::setw( 16 ) << a << std::endl; a = switch_endian( a ); std::cout << "Reversed: 0x" << std::setw( 16 ) << a << std::endl; std::cout << "Expected: 0x" << std::setw( 16 ) << b << std::endl; return 0; } /*************************************************** * switch_endian * * Reverses the order of the eight bytes in a * 64-bit unsigned integer. ***************************************************/ std::uint64_t switch_endian( std::uint64_t n ) { return ((n & UINT64_C( 0x00000000000000ff )) << 56) | ((n & UINT64_C( 0x000000000000ff00 )) << 40) | ((n & UINT64_C( 0x0000000000ff0000 )) << 24) | ((n & UINT64_C( 0x00000000ff000000 )) << 8) | ((n & UINT64_C( 0x000000ff00000000 )) >> 8) | ((n & UINT64_C( 0x0000ff0000000000 )) >> 24) | ((n & UINT64_C( 0x00ff000000000000 )) >> 40) | ((n & UINT64_C( 0xff00000000000000 )) >> 56); } /*************************************************** * C++23 and later * * You are not expected to use this in this exercise, * but the C++ standard library now provides a * function for reversing the bytes of an integer. * * If is included, we can write * * std::byteswap( n ) * * to reverse the order of the bytes. * * Thus, in C++23, * * std::byteswap( * UINT64_C( 0x0123456789abcdef ) * ) * * produces * * 0xefcdab8967452301. * * The purpose of this exercise is to understand how * the same operation can be implemented using masks * and bit shifts. ***************************************************/