Unions and enums Ready
main.c

                

Ready

Statements run 0 Lines printed 0
Ready

Keyboard: ← → step · Space play / pause · R reset · Esc exit classroom mode

How it works

The ideas behind the lab

Exactly what you watched happen, in plain steps.

Shared memory, named numbers

A union is declared like a struct, but every member starts at the same address: the union is only as big as its largest member and holds one member at a time. Writing one member overwrites the others, so a program must remember which member is valid — often with an enum "tag". An enum defines named int constants (0, 1, 2 … unless you give values), which makes code with fixed choices readable.

union Value { int i; float f; char c; };   // 4 bytes in total
union Value v;
v.i = 65;      // v.c now reads 'A' (same first byte)
v.f = 1.5f;    // overwrites i

enum Color { RED, GREEN, BLUE };           // 0, 1, 2
enum Level { LOW, MEDIUM = 5, HIGH };      // 0, 5, 6
enum Color c = GREEN;
struct vs union with the members int i; float f; char c;
struct union
Member addresses one after another all the same
Size 12 (4 + 4 + 1 + padding) 4 (the largest member)
Members valid at once all of them only the last one written
Writing one member leaves the others alone changes what the others read
Typical use a record with several fields a value that is one of several types

Unions

  1. union Name { members }; — same syntax as a struct.
  2. All members share memory; sizeof is the largest member (plus padding).
  3. Write one member, then read that same member.
  4. Reading another member gives the raw bytes reinterpreted — usually nonsense.
  5. Unions save memory when only one of several values is needed at a time.

Enums

  1. enum Name { A, B, C }; — A = 0, B = 1, C = 2.
  2. You may set values: { LOW = 1, HIGH = 10 }; the next name continues from the last value.
  3. Enum constants are ints: printf("%d", B) prints 1.
  4. They are ideal for switch cases and for array indexes (names[MON]).
  5. Prefer enums to many #defines: the names belong together and debuggers show them.

Tagged unions

  1. Put an enum "kind" and a union inside one struct.
  2. The kind says which union member is in use.
  3. Always set the kind together with the member.
  4. Read with switch (s.kind) and use only the matching member.
  5. This is how many programs store "a number OR a text OR …".
Walkthrough

Weekdays with an enum, shapes with a tagged union

Every line, explained.

1 #include <stdio.h>
2
3 enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }; 0 to 6.
4 const char *names[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
5
6 typedef enum { CIRCLE, RECT } ShapeKind;
7 typedef struct {
8 ShapeKind kind; The tag.
9 union {
10 double radius; Used when kind == CIRCLE.
11 struct { double w, h; } rect; Used when kind == RECT.
12 } u;
13 } Shape;
14
15 double area(Shape s)
16 {
17 switch (s.kind) { The tag decides which member to read.
18 case CIRCLE: return 3.14159 * s.u.radius * s.u.radius;
19 case RECT: return s.u.rect.w * s.u.rect.h;
20 }
21 return 0;
22 }
23
24 int main(void)
25 {
26 for (enum Day d = MON; d <= SUN; d++) An enum used as a loop counter and an index.
27 if (d >= SAT) printf("%s is weekend\n", names[d]); Sat is weekend / Sun is weekend
28 Shape a = { CIRCLE, { .radius = 1.0 } };
29 Shape b = { RECT };
30 b.u.rect.w = 2; b.u.rect.h = 3;
31 printf("%.2f %.2f\n", area(a), area(b)); Prints 3.14 6.00
32 printf("%zu\n", sizeof(Shape)); 4 + 4 padding + 16 (the bigger union member) = 24
33 return 0;
34 }
Common mistakes

Spot the bug

Mistakes almost every beginner makes — and how to fix them.

Reading the wrong union member

✗ Wrong
v.f = 1.5f;
printf("%d", v.i);   // 1069547520
✓ Right
v.f = 1.5f;
printf("%f", v.f);

Only the member written last holds a meaningful value.

Expecting all union members to keep their values

✗ Wrong
u.n = 42;
u.c = 'Z';
printf("%d", u.n);   // no longer 42
✓ Right
// use a struct if you need both values at the same time

All members share the same bytes; writing c changed part of n.

Forgetting the tag of a tagged union

✗ Wrong
s.u.radius = 2.0;   // kind still RECT
✓ Right
s.kind = CIRCLE;
s.u.radius = 2.0;

Code that trusts the tag would read rect.w from a circle.

Thinking enum values are strings

✗ Wrong
printf("%s", GREEN);   // crash
✓ Right
printf("%d", GREEN);              // 1
printf("%s", colorNames[GREEN]);   // "Green"

An enum constant is just an int. Keep a separate array of names to print them.

Two enums with the same constant name

✗ Wrong
enum Light { RED, GREEN };
enum Color { RED, BLUE };   // error: RED redeclared
✓ Right
enum Light { LIGHT_RED, LIGHT_GREEN };
enum Color { COLOR_RED, COLOR_BLUE };

All enum constants share one name space. Prefix them.

Practice

Check your understanding

Answer each question — you will see the explanation straight away.

0 / 5 correct
Question 1

union U { int i; double d; char c; }; — what is sizeof(union U) on a typical system?

Question 2

enum Color { RED, GREEN, BLUE }; — what is the value of BLUE?

Question 3

enum E { A = 3, B, C = 10, D }; — what are B and D?

Question 4

union V { int i; char c; } v; v.i = 66; — what does v.c read (little-endian)?

Question 5

Why does a tagged union need the enum "kind"?

Assessment

Unions & Enums quiz

Test yourself: 10 questions, 70% to pass. Create a free account to take the quiz, save your progress and work towards the certificate.