0

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!

Lundin
  • 195,001
  • 40
  • 254
  • 396
Vivekanand V
  • 340
  • 2
  • 12
  • 1
    Endianess takes hold from inception on the `uint32_t arr[2]`. Both of those `uint32_t` values are stored in platform-specific endian representation. That is not the case for the first sample and a `uint8_t` base array. Consider that. – WhozCraig Dec 14 '20 at 04:33
  • 1
    Aside, "On a little endian system, u would be equal to 0xa0b0ffeeddccbbaa" -> code `*(uint64_t *)array` risks alignment issues. – chux - Reinstate Monica Dec 14 '20 at 04:45
  • @WhozCraig Can you please clarify more ? :) – Vivekanand V Dec 14 '20 at 05:23
  • @chux-ReinstateMonica Can you elaborate more on alignment issues ? – Vivekanand V Dec 14 '20 at 05:23
  • See [What is data alignment? Why and when should I be worried when typecasting pointers in C?](https://stackoverflow.com/questions/38875369/what-is-data-alignment-why-and-when-should-i-be-worried-when-typecasting-pointe) – chux - Reinstate Monica Dec 14 '20 at 05:36
  • Example would speak louder than anything else. Think of what you're doing, but backward. [Look at this](https://coliru.stacked-crooked.com/a/17ebf380b7e91a7c). Consider what endian representation is doing with each of those `uint32_t` values in that array of two. – WhozCraig Dec 14 '20 at 05:53

1 Answers1

1

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.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Thankyou, very much for your answer! Because of your answer, I got the concept very clearly ! :) But, I've been using this technique conversion, for efficiency reasons. But, as per your advice I'm **going** to use ```memcpy``` / ```union``` ! :) – Vivekanand V Dec 14 '20 at 13:40