Assume identical common top struct members:
struct a {
int i1;
char c1;
short sa1[3];
};
struct b {
int i2;
char c2;
short sa2[3];
Are the following 2 line always equivalent (as in: yielding the same
lvalue) and allowed:
tmp.c1
((struct b*)&tmp)->c1
No, the behavior is undefined. It's not because the members might be a
different locations in the two structs; that's possible but unlikely.
The real reason is the anti-aliasing rules (6.5p7). Because those rules
make the behavior of such code undefined, the implementation is not
obligated to consider the possibility that an lvalue referring to a
"struct a" object refers to the same object as one that refers to a
"struct b" object. As a result, when implementing code such as the
following:
tmp.c1 = 1;
printf("%d\n", ((struct b*)&tmp)->c1);
An implementation is not required to notice that the printf() is
referring to the same object as the assignment statement. As a result,
it could, for instance, defer the writing the new value to tmp.c1 until
after executing the printf() call. That's pretty unlikely in this simple
case, but gets more likely in more complicated code when aggressive
optimization is turned on.
There's a special exception that allows you to access the "common
initial sequence" of any two struct types, using either struct type,
when they are both members of the same union (6.5.2.3p6):
union ab
{
struct a one;
struct b two;
} pair;
pair.one.c1 = 1
printf("%d\n", pair.two.c1);