C Unions
A union looks like a structure, but all its members share the same memory. Only one member holds a meaningful value at a time. Unions save memory when a value can be one of several types, but never two at once.
Structure and union compared
#include <stdio.h>
struct S { int i; double d; char c; };
union U { int i; double d; char c; };
int main(void) {
printf("struct: %zu bytes\n", sizeof(struct S));
printf("union: %zu bytes\n", sizeof(union U));
return 0;
}struct: 24 bytes union: 8 bytes
The structure has room for all three members (plus some padding the compiler adds for alignment). The union is only as big as its largest member, the double.
One value at a time
Writing one member of a union overwrites the others. Read the member you wrote last:
#include <stdio.h>
union Value {
int i;
float f;
};
int main(void) {
union Value v;
v.i = 42;
printf("as int: %d\n", v.i);
v.f = 3.5f; // now the int is overwritten
printf("as float: %.1f\n", v.f);
return 0;
}as int: 42 as float: 3.5
Tagged unions
A union does not remember which member is in use, so programs usually pair it with an enum "tag" inside a structure. This is a tagged union, a common pattern for values that can be of several kinds:
#include <stdio.h>
typedef enum { NUMBER, TEXT } Kind;
typedef struct {
Kind kind;
union {
double number;
const char *text;
} as;
} Item;
void printItem(Item it) {
if (it.kind == NUMBER) printf("number: %.2f\n", it.as.number);
else printf("text: %s\n", it.as.text);
}
int main(void) {
Item a = {NUMBER, {.number = 2.5}};
Item b = {TEXT, {.text = "hello"}};
printItem(a);
printItem(b);
return 0;
}number: 2.50 text: hello
When to use unions
Unions are a specialised tool: message formats where each message type has different fields, interpreters that store values of several types, and code close to hardware. In everyday programs a structure is usually the clearer choice. Reading a member other than the one last written reinterprets the same bytes as another type (the bytes of a float read as an int, for example), which is almost never what a program wants, so always keep track of which member is active.
Practice exercises
- Print the size of a union holding a
char, ashortand along long. - Add a third kind,
FLAGholding anint, to the taggedItemand print one. - Make an array of
Itemvalues of mixed kinds and print them all with a loop.