Prompted by this question:
The C11 standard states that a pointer to a union can be converted to a pointer to each of its members. From Section 6.7.2.1p17:
The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit-field, then to the unit in which it resides), and vice versa.
This implies you can do the following:
union u {
int a;
double b;
};
union u myunion;
int *i = (int *)&u;
double *d = (double *)&u;
u.a = 2;
printf("*i=%d\n", *i);
u.b = 3.5;
printf("*d=%f\n", *d);
But what about the reverse: in case of the above union, can an int *
or double *
be safely converted to a union u *
? Consider the following code:
#include <stdio.h>
union u {
int a;
double b;
};
void f(int isint, union u *p)
{
if (isint) {
printf("int value=%d\n", p->a);
} else {
printf("double value=%f\n", p->b);
}
}
int main()
{
int a = 3;
double b = 8.25;
f(1, (union u *)&a);
f(0, (union u *)&b);
return 0;
}
In this example, pointers to int
and double
, both of which are members of union u
, are passed to a function where a union u *
is expected. A flag is passed to the function to tell it which "member" to access.
Assuming, as in this case, that the member accessed matches the type of the object that was actually passed in, is the above code legal?
I compiled this on gcc 6.3.0 with both -O0
and -O3
and both gave the expected output:
int value=3
double value=8.250000
double
requires eight-byte alignment, then the union does too. But theint a
may have only four-byte alignment, in which case the behavior of converting&a
tounion u *
is not defined. – Apure