Search code examples
arrayscpointersmemoryendianness

How endianness swaps the order of elements, when converting two elements of uint32_t array to a single uint64_t?


I am confused as to how, endianness swaps the ordering of elements of a uint32_t array when converted to a uint64_t and vice-versa.

If I'm dealing with bytes stored in a uint8_t array of 8 elements, if I directly convert it to a uint64_t using pointer casting and dereference like this:

uint8_t array[8] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0xb0, 0xa0};
uint64_t u = *(uint64_t *)array; 

On a little endian system, u would be equal to 0xa0b0ffeeddccbbaa

But, if I have a uint32_t array like this:

uint32_t arr[2] = {0xaabbccdd, 0xeeffb0a0} ;
uint64_t U = *(uint64_t *)arr;

On a little endian system, U becomes 0xeeffb0a0aabbccdd

I intuitively understand the former case, but the latter, with the uint32_t is confusing! I have trouble visualizing the memory layout, during conversion, in the latter case... Every help, will be greatly appreciated!


Solution

  • Endianess applies individually on every integer of 16 bits or larger. That is, on a little endian machine, a 32 bit integer 0xaabbccdd is stored as dd cc bb aa.

    So an array of two 32 integers uint32_t [2] with the values 0x11223344 and 0x55667788 are stored as
    44 33 22 11 and 88 77 66 55 respectively. In an array, items are guaranteed to get stored contiguously, so in this case the memory will look like 44 33 22 11 88 77 66 55.

    A 64 bit integer 0x1122334455667788 is however stored as 88 77 66 55 44 33 22 11, because again, endianess applies individually to each integer. This is why you can't re-interpret the memory layout of two 32 bit integers as a 64 bit integer on little endian machines.

    If the CPU had been big endian however, the uint32_t [2] would have been stored as:
    11 22 33 44 55 66 77 88 and then it happens to get the same representation as a uint64_t with the value 0x1122334455667788.


    As a sidenote, the *(uint64_t *)array conversions in your code are undefined behavior because they violate strict pointer aliasing and could possibly also give misalignment. To convert between different memory types safely, you need to use bit shifts, memcpy or union.