I am playing with little endian/big endian conversion and found something that a is a bit confusing but also interesting.
In first example, there is no problem using bit shift to convert byte order for type of uint32_t
. It basically cast a uint32_t
integer to an array of uint8_t
and try to access each byte and bit shift.
Example #1:
uint32_t htonl(uint32_t x)
{
uint8_t *s = (uint8_t*)&x;
return (uint32_t)(s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]);
}
However, if I try to do something similar on a uint64_t
below, the compiler throws a warning about 's[0] width is less than 56 bits` as in Example #2 below.
Example #2:
uint64_t htonl(uint64_t x)
{
uint8_t *s = (uint8_t*)&x;
return (uint64_t)(s[0] << 56 ......);
}
To make it work, I have to fetch each byte into a uint64_t
so I can do bit shift without any errors as in Example #3 below.
Example #3:
uint64_t htonll2(uint64_t x)
{
uint64_t byte1 = x & 0xff00000000000000;
uint64_t byte2 = x & 0x00ff000000000000;
uint64_t byte3 = x & 0x0000ff0000000000;
uint64_t byte4 = x & 0x000000ff00000000;
uint64_t byte5 = x & 0x00000000ff000000;
uint64_t byte6 = x & 0x0000000000ff0000;
uint64_t byte7 = x & 0x000000000000ff00;
uint64_t byte8 = x & 0x00000000000000ff;
return (uint64_t)(byte1 >> 56 | byte2 >> 40 | byte3 >> 24 | byte4 >> 8 |
byte5 << 8 | byte6 << 24 | byte7 << 40 | byte8 << 56);
}
I am a little bit confused by Example #1
and Example #2
, as far as I understand, both s[i]
is of uint8_t
size, but somehow if it only shift 32 bits or less there is no problem at all, but there is an issue when shifting like 56 bits. I am running this program on Ubuntu with GCC 8.3.0.
Does the compiler implicitly convert s[i]
into 32-bit numbers in this case? sizeof(s[0])
is 1 when I added debug messages to that.
The s[0]
expression has an 8-bit wide integral type, which is promoted to a 32-bit unsigned integer when operated on by the shift operator – so s[0] << 24
in the first example works OK, as the shift by 24 does not exceed the uint
length.
OTOH the shift by 56 bits moves data outside the result's length as the offset exceeds the length of integer, so it certainly causes a loss of information, hence the warning.