I just want to ask if my method is correct to convert from little endian to big endian, just to make sure if I understand the difference.
I have a number which is stored in little-endian, here are the binary and hex representations of the number:
0001 0010 0011 0100 0101 0110 0111 1000 12345678
In big-endian format I believe the bytes should be swapped, like this:
1000 0111 0110 0101 0100 0011 0010 0001 87654321
Is this correct?
Also, the code below attempts to do this but fails. Is there anything obviously wrong or can I optimize something? If the code is bad for this conversion can you please explain why and show a better method of performing the same conversion?
uint32_t num = 0x12345678; uint32_t b0,b1,b2,b3,b4,b5,b6,b7; uint32_t res = 0; b0 = (num & 0xf) << 28; b1 = (num & 0xf0) << 24; b2 = (num & 0xf00) << 20; b3 = (num & 0xf000) << 16; b4 = (num & 0xf0000) << 12; b5 = (num & 0xf00000) << 8; b6 = (num & 0xf000000) << 4; b7 = (num & 0xf0000000) << 4; res = b0 + b1 + b2 + b3 + b4 + b5 + b6 + b7; printf("%d\n", res);
"I swap each bytes right?" -> yes, to convert between little and big endian, you just give the bytes the opposite order. But at first realize few things: size of uint32_t is 32bits, which is 4 bytes, which is 8 HEX digits. mask 0xf retrieves the 4 least significant bits, to retrieve 8 bits, you need 0xff.
To do this, we shift the rightmost 8 bits by 24 to the left so that it becomes the leftmost 8 bits. We left shift the right middle byte by 16 (to store it as the left middle byte) We left shift the left middle byte by 8 (to store it as the right muddle byte) We finally left shift the leftmost byte by 24 to the left.
In hex, this number would be represented as 230116 (or 0x2301). The important thing to remember is that the endianness describes the order in which a sequence of bytes are stored. Each byte is made up of two digits which represents the upper or lower 4 bits of the value.
Big-endian is an order in which the "big end" (most significant value in the sequence) is stored first, at the lowest storage address. Little-endian is an order in which the "little end" (least significant value in the sequence) is stored first.
OP's sample code is incorrect.
Endian conversion works at the bit and 8-bit byte level. Most endian issues deal with the byte level. OP code is doing a endian change at the 4-bit nibble level. Recommend instead:
// Swap endian (big to little) or (little to big) uint32_t num = 9; uint32_t b0,b1,b2,b3; uint32_t res; b0 = (num & 0x000000ff) << 24u; b1 = (num & 0x0000ff00) << 8u; b2 = (num & 0x00ff0000) >> 8u; b3 = (num & 0xff000000) >> 24u; res = b0 | b1 | b2 | b3; printf("%" PRIX32 "\n", res);
If performance is truly important, the particular processor would need to be known. Otherwise, leave it to the compiler.
[Edit] OP added a comment that changes things.
"32bit numerical value represented by the hexadecimal representation (st uv wx yz) shall be recorded in a four-byte field as (st uv wx yz)."
It appears in this case, the endian of the 32-bit number is unknown and the result needs to be store in memory in little endian order.
uint32_t num = 9; uint8_t b[4]; b[0] = (uint8_t) (num >> 0u); b[1] = (uint8_t) (num >> 8u); b[2] = (uint8_t) (num >> 16u); b[3] = (uint8_t) (num >> 24u);
[2016 Edit] Simplification
... The type of the result is that of the promoted left operand.... Bitwise shift operators C11 §6.5.7 3
Using a u
after the shift constants (right operands) results in the same as without it.
b3 = (num & 0xff000000) >> 24u; b[3] = (uint8_t) (num >> 24u); // same as b3 = (num & 0xff000000) >> 24; b[3] = (uint8_t) (num >> 24);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With