Unions are an interesting construct that you’re likely to find in C programs.
A union looks similar to a struct
on the outside, but it has a special quality that it can only hold one of its declared values at a time.
So, what happens if we write to one member and then read from inactive fields? Let’s try and see!
#include <stdio.h>
union s {
int a;
float b;
double c;
unsigned long d;
};
void print_union(union s *mu){
printf("a %d\n", mu->a);
printf("b %f\n", mu->b);
printf("c %f\n", mu->c);
printf("d %lu\n", mu->d);
printf("-----------\n");
}
int main(int argc, char **argv) {
union s mu;
mu.a = -9;
print_union(&mu);
mu.b = 11.3;
print_union(&mu);
mu.c = 137.101754;
print_union(&mu);
mu.d = 7267383982;
print_union(&mu);
return 0;
}
Running this on the following system…
Linux trainwreck-PC 5.4.0-47-generic #51-Ubuntu SMP Fri Sep 4 19:50:52 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
gcc (Ubuntu 9.3.0-10ubuntu2) 9.3.0
… yields this:
a -9
b -nan
c 0.000000
d 140737488355319
-----------
a 1093979341
b 11.300000
c 0.000000
d 140734287367373
-----------
a -1852127337
b -0.000000
c 137.101754
d 4639027855691007895
-----------
a -1322550610
b -0.000000
c 0.000000
d 7267383982
-----------
As you can see, each time the print_union
subroutine is called, only the most recently assigned member displays a correct value.
So, where do those other values come from? The C standard doesn’t say, so it’s undefined behavior.
It’s likely the union memory region being erroneously interpreted as some other type. If you run the above program multiple times, some values may vary while others don’t, so it’s not just memory noise. For instance, -9 converted to unsigned long
does not equal the value displayed by print_union
on the first case where we have a = -9
.
Using union
‘s this way voids your C warranty, so don’t do it. But in case you’re curious, this little program illustrates what you should expect from reading inactive C union
members.