C Tutorial
C Unions
A union stores one of several types in the same memory. Only one member is valid at a time.
Same storage, one member at a time
A struct gives every field its own memory. A union overlays its members on the same bytes. Writing one member overwrites the others. Only the member you last stored is valid to read.
Use a union when a value is one type or another, never both at once: an integer or a floating-point number, a tag that picks which view is live. Do not use it as a smaller struct. The members are not a list of fields that all exist together.
Define a union
The syntax looks like a struct: the keyword union, a type name, a brace block of members, and a semicolon after the closing brace. Declare a variable as union Number n;. Access a member with the dot, the same way you access a struct field.
Example
#include <stdio.h>
union Number {
int i;
double d;
};
int main(void) {
union Number n;
n.i = 7;
printf("int: %d\n", n.i);
return 0;
}After n.i = 7, n.i is the live member. Do not print n.d yet. That member has not been stored.
Writing a second member replaces the first
Store a double in the same union and the integer view is no longer valid. The bits that meant 7 are gone. Read the member you just wrote.
Example
#include <stdio.h>
union Number {
int i;
double d;
};
int main(void) {
union Number n;
n.i = 7;
printf("int: %d\n", n.i);
n.d = 2.5;
printf("double: %.1f\n", n.d);
return 0;
}Compile this at /c/try. After the second assignment, print n.d, notn.i. Only one member is valid.
Reading a member you did not last write is not a second field. It is leftover bits. Treat that as a bug unless you are doing a later, careful trick.
The size is the largest member
A struct’s size is (at least) the sum of its fields. A union’s size is the size of its largest member. All members start at the same address. That is why they cannot hold independent values at the same time.
Example
#include <stdio.h>
struct Both {
int i;
double d;
};
union Either {
int i;
double d;
};
int main(void) {
printf("struct bytes: %zu\n", sizeof(struct Both));
printf("union bytes: %zu\n", sizeof(union Either));
return 0;
}%zu prints a sizeof result. The struct is larger: it keeps both an intand a double. The union is as wide as the double alone.
Union versus struct
| struct | union | |
|---|---|---|
| Memory | Each field has its own bytes | Members overlay the same bytes |
| Valid at once | Every field | Only the member you last stored |
| Size | Sum of the fields (plus padding) | Size of the largest member |
If you need a point with x and y together, that is a struct. If you need a slot that is sometimes an int and sometimes a double, that is a union.
Keep a tag nearby
A union does not remember which member you stored. If the program must decide later, keep a separateenum (or an int) that names the live member. Read that tag first, then read the matching union member.
Next: pointers — an address of an object, and the * that reads the value there.
Worked examples
The short listings above are there so you can see the grammar. The programs here use the same statements on quantities that already have units: a speed, a pH, a count of bases. They are classroom numbers. Air resistance is ignored. g is 9.81 m/s² unless a line says otherwise.
Open them in the C editor at /c/try. Change one measurement and check whether the result still has the right unit.
Engineering
ADC counts or volts
An analogue-to-digital converter returns an integer count. After calibration you might treat the same register as a voltage. A union is a way to name those two views of one memory slot. Only one view is valid at a time.
Writing r.volts overwrites the bits that were r.counts. This listing does that on purpose so you see the two interpretations, not so you should mix them in production.
Type punning through a union is a historical pattern. Modern C prefers memcpy into the type you mean. The example is here to show the overlap, not as a style guide.
Example
#include <stdio.h>
int main(void) {
union Reading {
int counts;
float volts;
};
union Reading r;
r.counts = 512;
printf("counts = %d\n", r.counts);
r.volts = 3.30f;
printf("volts = %.2f\n", r.volts);
return 0;
}Physics
One slot in a packet
Old telemetry packed whatever fit. A float temperature and an int timestamp cannot both be live in the same four bytes. The union is the warning: pick a member and stick to it for that packet.
Example
#include <stdio.h>
int main(void) {
union Packet {
int t_ms;
float temp_c;
};
union Packet p;
p.temp_c = 21.5f;
printf("temp field = %.1f\n", p.temp_c);
return 0;
}