Skip to content

Instantly share code, notes, and snippets.

@shangdawei
Last active December 20, 2023 10:02
Show Gist options
  • Save shangdawei/71dc301061add59bec540c887805d410 to your computer and use it in GitHub Desktop.
Save shangdawei/71dc301061add59bec540c887805d410 to your computer and use it in GitHub Desktop.
Big Endian and Little Endian Convert
// read a little-endian number from memory into native byte order.
uint16_t read_le16( const void* p );
uint32_t read_le32( const void* p ); // see read_le16
uint64_t read_le64( const void* p ); // see read_le16
// read a big-endian number from memory into native byte order.
uint16_t read_be16( const void* p );
uint32_t read_be32( const void* p ); // see read_be16
uint64_t read_be64( const void* p ); // see read_be16
// write a little-endian number to memory in native byte order.
void write_le16( void* p, uint16_t x );
void write_le32( void* p, uint32_t x ); // see write_le16
void write_le64( void* p, uint64_t x ); // see write_le16
// write a big-endian number to memory in native byte order.
void write_be16( void* p, uint16_t x );
void write_be32( void* p, uint32_t x ); // see write_be16
void write_be64( void* p, uint64_t x ); // see write_be16
/**
* zero-extend \<size\> (truncated to 8) bytes of little-endian data to uint64_t,
* starting at address \<p\> (need not be aligned).
**/
uint64_t movzx_le64( const uint8_t * p, size_t size_bytes );
uint64_t movzx_be64( const uint8_t * p, size_t size_bytes );
/**
* sign-extend \<size\> (truncated to 8) bytes of little-endian data to int64_t,
* starting at address \<p\> (need not be aligned).
**/
int64_t movsx_le64( const uint8_t * p, size_t size_bytes );
int64_t movsx_be64( const uint8_t * p, size_t size_bytes );
// read a little-endian number from memory into native byte order.
uint16_t read_le16( const void* p )
{
return TO_LE16( *(uint16_t* )p );
}
uint32_t read_le32( const void* p )
{
return TO_LE32( *(uint32_t* )p );
} // see read_le16
uint64_t read_le64( const void* p )
{
return TO_LE64( *(uint64_t* )p );
} // see read_le16
// read a big-endian number from memory into native byte order.
uint16_t read_be16( const void* p )
{
return TO_BE16( *(uint16_t* )p );
}
uint32_t read_be32( const void* p )
{
return TO_BE32( *(uint32_t* )p );
} // see read_be16
uint64_t read_be64( const void* p )
{
return TO_BE64( *(uint64_t* )p );
} // see read_be16
// write a little-endian number to memory in native byte order.
void write_le16( void* p, uint16_t x )
{
*(uint16_t*) p = TO_LE16( x );
}
void write_le32( void* p, uint32_t x )
{
*(uint32_t*) p = TO_LE32( x );
} // see write_le16
void write_le64( void* p, uint64_t x )
{
*(uint64_t*) p = TO_LE64( x );
} // see write_le16
// write a big-endian number to memory in native byte order.
void write_be16( void* p, uint16_t x )
{
*(uint16_t*) p = TO_BE16( x );
}
void write_be32( void* p, uint32_t x )
{
*(uint32_t*) p = TO_BE32( x );
} // see write_be16
void write_be64( void* p, uint64_t x )
{
*(uint64_t*) p = TO_BE64( x );
} // see write_be16
/**
* zero-extend \<size\> (truncated to 8) bytes of little-endian data to uint64_t,
* starting at address \<p\> (need not be aligned).
**/
uint32_t std_min( size_t a, size_t b )
{
if ( a < b )
return a;
else
return b;
}
uint64_t movzx_le64( const uint8_t * p, size_t size_bytes )
{
uint64_t number = 0;
for ( uint32_t i = 0; i < std_min( size_bytes, (size_t) 8u ); i++ )
number |= ( (uint64_t) p[ i ] ) << ( i * 8 );
return number;
}
uint64_t movzx_be64( const uint8_t * p, size_t size_bytes )
{
uint64_t number = 0;
for ( uint32_t i = 0; i < std_min( size_bytes, (size_t) 8u ); i++ )
{
number <<= 8;
number |= p[ i ];
}
return number;
}
/**
* sign-extend \<size\> (truncated to 8) bytes of little-endian data to int64_t,
* starting at address \<p\> (need not be aligned).
**/
inline int64_t SignExtend( uint64_t bits, size_t size_bytes )
{
// no point in sign-extending if >= 8 bytes were requested
if ( size_bytes < 8 )
{
const uint64_t sign_bit = BIT64( ( size_bytes * 8 ) - 1 );
// number would be negative in the smaller type,
// so sign-extend, i.e. set all more significant bits.
if ( bits & sign_bit )
{
const uint64_t valid_bit_mask = ( sign_bit + sign_bit ) - 1;
bits |= ~valid_bit_mask;
}
}
const int64_t number = (int64_t) ( bits );
return number;
}
int64_t movsx_le64( const uint8_t * p, size_t size_bytes )
{
const uint64_t number = movzx_le64( p, size_bytes );
return SignExtend( number, size_bytes );
}
int64_t movsx_be64( const uint8_t * p, size_t size_bytes )
{
const uint64_t number = movzx_be64( p, size_bytes );
return SignExtend( number, size_bytes );
}
#if BYTE_ORDER == __ORDER_BIG_ENDIAN__
//Host byte order to network byte order (at compile time)
#define HTONS(value) (value)
#define HTONL(value) (value)
//Network byte order to host byte order (at compile time)
#define NTOHS(value) (value)
#define NTOHL(value) (value)
//Host byte order to little-endian byte order (at compile time)
#define HTOLE16(value) __SWAP16__(value)
#define HTOLE32(value) __SWAP32__(value)
#define HTOLE64(value) __SWAP64__(value)
//Little-endian byte order to host byte order (at compile time)
#define LETOH16(value) __SWAP16__(value)
#define LETOH32(value) __SWAP32__(value)
#define LETOH64(value) __SWAP64__(value)
//Host byte order to big-endian byte order (at compile time)
#define HTOBE16(value) (value)
#define HTOBE32(value) (value)
#define HTOBE64(value) (value)
//Big-endian byte order to host byte order (at compile time)
#define BETOH16(value) (value)
#define BETOH32(value) (value)
#define BETOH64(value) (value)
#else
//Host byte order to network byte order (at compile time)
#define HTONS(value) __SWAP16__(value)
#define HTONL(value) __SWAP32__(value)
//Network byte order to host byte order (at compile time)
#define NTOHS(value) __SWAP16__(value)
#define NTOHL(value) __SWAP32__(value)
//Host byte order to little-endian byte order (at compile time)
#define HTOLE16(value) (value)
#define HTOLE32(value) (value)
#define HTOLE64(value) (value)
//Little-endian byte order to host byte order (at compile time)
#define LETOH16(value) (value)
#define LETOH32(value) (value)
#define LETOH64(value) (value)
//Host byte order to big-endian byte order (at compile time)
#define HTOBE16(value) __SWAP16__(value)
#define HTOBE32(value) __SWAP32__(value)
#define HTOBE64(value) __SWAP64__(value)
//Big-endian byte order to host byte order (at compile time)
#define BETOH16(value) __SWAP16__(value)
#define BETOH32(value) __SWAP32__(value)
#define BETOH64(value) __SWAP64__(value)
#endif
#if BYTE_ORDER == __ORDER_BIG_ENDIAN__
// convert a little-endian number to/from native byte order.
# define TO_LE16(x) swap16(x)
# define TO_LE32(x) swap32(x)
# define TO_LE64(x) swap64(x)
// convert a big-endian number to/from native byte order.
# define TO_BE16(x) (x)
# define TO_BE32(x) (x)
# define TO_BE64(x) (x)
#else
// convert a little-endian number to/from native byte order.
# define TO_LE16(x) (x)
# define TO_LE32(x) (x)
# define TO_LE64(x) (x)
// convert a big-endian number to/from native byte order.
# define TO_BE16(x) swap16(x)
# define TO_BE32(x) swap32(x)
# define TO_BE64(x) swap64(x)
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment