The fact that GCC is warning about unions doesn’t necessarily mean that unions don’t currently work. But here’s a slightly less simple example than yours:
#include <stdio.h>
struct B {
int i1;
int i2;
};
union A {
struct B b;
double d;
};
int main() {
double d = 3.0;
#ifdef USE_UNION
((union A*)&d)->b.i2 += 0x80000000;
#else
((int*)&d)[1] += 0x80000000;
#endif
printf("%g\n", d);
}
Output:
$ gcc --version
gcc (GCC) 4.3.4 20090804 (release) 1
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gcc -oalias alias.c -O1 -std=c99 && ./alias
-3
$ gcc -oalias alias.c -O3 -std=c99 && ./alias
3
$ gcc -oalias alias.c -O1 -std=c99 -DUSE_UNION && ./alias
-3
$ gcc -oalias alias.c -O3 -std=c99 -DUSE_UNION && ./alias
-3
So on GCC 4.3.4, the union “saves the day” (assuming I want the output “-3”). It disables the optimisation that relies on strict aliasing and that results in the output “3” in the second case (only). With -Wall, USE_UNION also disables the type-pun warning.
I don’t have gcc 4.4 to test, but please give this code a go. Your code in effect tests whether the memory for d
is initialised before reading back through a union: mine tests whether it is modified.
Btw, the safe way to read half of a double as an int is:
double d = 3;
int i;
memcpy(&i, &d, sizeof i);
return i;
With optimisation on GCC, this results in:
int thing() {
401130: 55 push %ebp
401131: 89 e5 mov %esp,%ebp
401133: 83 ec 10 sub $0x10,%esp
double d = 3;
401136: d9 05 a8 20 40 00 flds 0x4020a8
40113c: dd 5d f0 fstpl -0x10(%ebp)
int i;
memcpy(&i, &d, sizeof i);
40113f: 8b 45 f0 mov -0x10(%ebp),%eax
return i;
}
401142: c9 leave
401143: c3 ret
So there’s no actual call to memcpy. If you aren’t doing this, you deserve what you get if union casts stop working in GCC 😉