So, I have this code here:
struct mystruct {
char a;
union {
char a[8];
char b[16];
} u;
};
void fuu(void)
{
struct mystruct s;
printf("%ld %ld\n", sizeof(s), &((struct mystruct *)0)->u.b);
}
The snippet that confuses me is:
&((struct mystruct *)0)->u.b
As far as I can understand it, firstly pointer to struct is casted to lvalue int of 0(what?)
Then, u.b is taken out of this pointer(which should be a pointer to the start of char array b)
Then address of this pointer is taken and printed to the screen.
The most confusing moment of all this is cast to 0.
Can someone explain in detail what is happening in this snippet?
CodePudding user response:
Let's break it down a bit. Assume that we have a variable x
that is a pointer to a mystruct
:
struct mystruct *x;
And replace that in the expression in question:
&(x->u.b)
This takes the address of the member u.b
in the struct that x
points to. We can guess that this address should be slightly higher than x
itself, because u
is not the first member in the struct.
Then, add the fact that x
is zero:
struct mystruct *x = (struct mystruct *)0;
Then, the value of the expression above will be slightly higher than 0. Or in other words, it will be the offset of u.b
within the memory layout of the struct.
In fact, at least on my machine it's 1, because the only member in the struct before u
is char a
, which takes up 1 byte.*
Another way to do this is to use the offsetof
macro defined in stddef.h
:
#include <stddef.h>
...
printf("%ld %ld\n", sizeof(s), offsetof(struct mystruct, u.b));
It has the same effect, but it might be easier to understand what the code is trying to do.
* And none of the members of the union have greater alignment requirements. Try changing either of the members of the union from char
to int
- what happens?
The offset is printed as 4 instead of 1, because an
int
needs to be stored in an address divisible by 4. So the struct will contain one byte forchar a
, three unused bytes for alignment, and then the union.