Intermediate · Structs, unions, enums and files · topic 33 of 60 · 25 min
Unions, enums and memory layout
Explanation
enum
enum OrderStatus { PENDING, PAID, SHIPPED, DELIVERED, CANCELLED }; /* 0, 1, 2, 3, 4 */
enum Http { OK = 200, NOT_FOUND = 404, SERVER_ERROR = 500 }; /* explicit values */
enum OrderStatus s = PAID;
switch (s) {
case PENDING: puts("Waiting for payment"); break;
case PAID: puts("Packing your order"); break;
case SHIPPED: puts("On the way"); break;
case DELIVERED: puts("Delivered"); break;
case CANCELLED: puts("Cancelled"); break;
}Enum constants are just ints, so nothing stops s = 42; and printing s prints a number. Keep an array of names indexed by the enum if you need text: const char *status_name[] = {"PENDING", "PAID", …};.
union
union Value {
int i;
float f;
char text[8];
}; /* sizeof(union Value) is 8: the largest member */
union Value v;
v.i = 42;
v.f = 3.5f; /* overwrites the same bytes: v.i is no longer meaningful */A union saves memory when a variable holds one of several kinds of data at a time, for example a configuration value that can be a number OR a string, or a message from a device that has different formats. Reading a member other than the one last written gives the raw bytes reinterpreted; C allows it, but it is platform-specific.
Tagged unions
typedef enum { PAY_UPI, PAY_CARD, PAY_COD } PayKind;
typedef struct {
PayKind kind; /* the tag: which member is valid */
union {
char vpa[50]; /* for UPI */
struct { char last4[5]; char network[12]; } card;
} as;
} Payment;
void describe(const Payment *p) {
switch (p->kind) {
case PAY_UPI: printf("UPI %s\n", p->as.vpa); break;
case PAY_CARD: printf("%s card ending %s\n", p->as.card.network, p->as.card.last4); break;
case PAY_COD: printf("Cash on delivery\n"); break;
}
}Padding and alignment
Processors read data fastest (and on some, only) at addresses that are multiples of the data's size: a 4-byte int at a multiple of 4. To keep members aligned, the compiler inserts unused padding bytes inside structs, and at the end so arrays of the struct stay aligned. So sizeof a struct can be larger than the sum of its members.
struct Bad { char a; int b; char c; }; /* typical x86-64: 12 bytes */
offset: a@0, [3 padding], b@4..7, c@8, [3 padding] → 12
struct Good { int b; char a; char c; }; /* typical x86-64: 8 bytes */
offset: b@0..3, a@4, c@5, [2 padding] → 8Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Unions, enums and memory layout · 1/6
In this lesson you will use enums, unions, and see how structs are laid out in memory.
Prefer a video by a teacher? Find free videos on “c enum union structure padding alignment explained” on YouTube ↗
In real life: A smart-meter message
A smart electricity meter sends either a reading, an alarm or a firmware version. The receiving software stores each message in a tagged union, saving memory on a small gateway device, and switches on the tag to process it.
typedef enum { MSG_READING, MSG_ALARM, MSG_VERSION } MsgKind;
typedef struct {
MsgKind kind;
union {
struct { uint32_t meter_id; uint32_t units_wh; } reading;
uint16_t alarm_code;
char version[12];
} body;
} MeterMsg;Practice (0/3 done)
enum Level { LOW, MEDIUM = 5, HIGH }; What is HIGH?
On a typical x86-64 system, sizeof(struct { char a; double d; char b; }) is…
Model a payment in C as a tagged union (UPI with a VPA string, card with last 4 digits and network, cash on delivery with nothing extra). Write describe(const Payment *p) with a switch on the tag, create one of each kind, and print sizeof(Payment). Then reorder a padded struct of your own to make it smaller and print both sizes.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Reading and writing text filesStructs, unions, enums and files · same module
- Unions and narrowingFrontend Web Development · TypeScript basics
- Object types, interfaces and unionsJavaScript Programming (language in depth) · TypeScript basics
- Data, enum and sealed classes, and objectsKotlin and Android App Development · Classes, objects and collections
- Enums and OptionRust Programming · Structs, enums and pattern matching
- Dart 3: enums, records, patterns and sealed classesFlutter and Dart · Null safety and object-oriented Dart
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What is the size of a union?
Answer: At least the size of its largest member
Members overlap (plus possible padding).
What are enum constants in C?
Answer: Named int constants
They behave like ints.
Why does the compiler add padding to structs?
Answer: To keep members aligned for fast (or legal) access
Alignment.
What is a tagged union?
Answer: A struct with an enum saying which union member is valid
The tag makes it safe to use.
let status: "pending" | "paid" | "failed" = "pending"; Which assignment is an error?Related
Answer: status = "refunded";
"refunded" is not one of the three allowed literal values.
From Unions and narrowing
What makes a union "discriminated"?Related
Answer: Every member has a common field with a different literal value
The shared literal field lets TypeScript narrow precisely.
Which is like Java's static members?Related
Answer: companion object
Companion object members are accessed through the class name.
What can an enum variant hold in Rust?Related
Answer: Any data: none, a tuple of values, or named fields
Rust variants can be unit-like, tuple-like or struct-like.
From Enums and Option
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 2 more topics in “Structs, unions, enums and files” before its exam: Reading and writing text files, Binary files and records.
- Module 7 exam: Structs, unions, enums and files · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, The preprocessor, multi-file programs and make. 60 topics left in the course before the final exam.