Which logically tries to convert array to a structure and throws no warnings.
There is nothing logical behind that code. More correctly, the code nonsensically tries to convert an array to a structure. However, C allows a lot of nonsense and when you invoke undefined behavior, everything can happen.
This is what happens behind the lines:
void* arr[2]
is an array of two pointers, which will have the same size as the address bus of the given system. Let us assume that the address bus is 32 bits.
{(int*)1, (int*)2};
then takes two integer literals and cast each of them to a pointer. This is fine in C. So we have int two pointers with addresses 0x00000001 and 0x00000002 respectively.
- The int pointers are then stored in the void pointer array without problems, since there is no explicit cast needed between a void pointer and another type of pointer.
- Then
(struct tree*)arr
wildly casts the array into a struct type. This breaks the so-called "strict aliasing rule" and this is undefined behavior. Here your program may very well crash and burn, because there are several potential problems.
- The alignment of the data members of the struct is not necessarily compatible with the alignment of the pointer variables, and there may be padding bytes in the struct. - Furthermore there is nothing saying that the struct is smaller than the 2 pointers. In case it is larger, the program will attempt to access memory out-of-bounds as it reads past the end of the array.
- Also the representation of
char
on the given system may be anything. They may be 8 bits, they may be 16 bits, they may or may not come with a sign bit.
- With some luck, the undefined behavior on your given machine could turn out like this: Lets assume characters are 8 bit unsigned and again that pointers are 32 bits. Lets assume there is no padding or alignment issues. Lets assume that the program doesn't crash and burn when you execute the code. In that case, the struct would take the 2 first encountered bytes of the pointer array and treat them as data. Since the array constains data 0x0000000100000002, the two first bytes is 0x00 and 0x00.
apple
and leaf
would then contain the values 0 and 0 respectively. But this is also endianess-dependent, which byte in the pointer address that goes where depends on whether your machine uses little endian or big endian.
Is that the way I convert array to a structure?
No, this is very bad code. There is nothing correct about it. Never write code like this.
So what is the correct way of converting an array to a struct?
Simply do:
char arr[2] = {1, 2};
myStruct.apple = arr[1];
myStruct.leaf = arr[2];
That's the only 100% bullet-proof way. If you wish to use memcpy() or similar, to reduce the number of manual assignments, you have to write defensive programming to protect yourself against struct padding:
static_assert(sizeof(arr) == sizeof(myStruct), "ERR: struct padding detected");
memcpy(&myStruct, arr, sizeof(myStruct));