5.1.25 · D2C Programming

Visual walkthrough — Enumerations

1,602 words7 min readBack to topic

This is the parent topic taken apart slowly. Every symbol here is earned before use. If you have never seen an enum, start at line one — nothing is assumed.


Step 1 — A name is really just a locker number

WHAT. We line up three empty lockers and stick a paper name-tag on each: RED, GREEN, BLUE. The machine does not read tags; it only reads locker numbers. Our whole job is to work out which number hides behind each name.

WHY. Before any rule, you must believe the core secret: in C an enumerator is not a special object — it is literally an integer wearing a name-tag. This is the foundation the parent note calls "sticky notes on lockers". Everything else is bookkeeping about which number lands on which tag.

PICTURE. Three grey lockers, one blue name-tag each. The number inside the locker is what we are hunting.

Figure — Enumerations

Step 2 — The first tag always gets 0

WHAT. We fill in the very first locker. The C rule: the first enumerator with no number written next to it gets the value .

  • — the 0th (first) enumerator in the list. We count from 0 because C counts from 0.
  • — its hidden integer.
  • — the starting value, chosen by the language so it lines up neatly with array indices later.

WHY 0 and not 1? Because C arrays start at index 0 (see Arrays in C). If enums also start at 0, an enumerator can be used directly as an array position with no "+1" fudge. That design choice is the reason for this exact number.

PICTURE. The RED locker fills with a bold 0.

Figure — Enumerations

Step 3 — Every next tag is "previous + 1"

WHAT. For every enumerator after the first that has no explicit number, we compute it by taking the previous one and adding 1:

  • — the enumerator at position (the one we are filling now).
  • — the enumerator immediately before it in the written list.
  • — take that neighbour's number and step up by one.

WHY this tool — a recurrence? A recurrence is a rule that defines each term using the term before it. We choose it because the C standard literally says "one greater than the previous enumerator". It answers the question "if I only know 0 and the phrase 'add one', can I generate the whole list?" — yes: apply the rule repeatedly.

Applying it to {RED, GREEN, BLUE}:

PICTURE. Orange "+1" arrows hop locker-to-locker: 0 → 1 → 2.

Figure — Enumerations

Step 4 — Writing an explicit number teleports the counter

WHAT. You may pin a number to any tag with =. That number overrides the "+1" for that tag only:

enum Status { OK = 1, WARN = 5, ERR, FATAL = 5 };
  • OK = 1 — explicit, so (the teleport ignores 0).
  • WARN = 5 — explicit again, teleport to 5.
  • ERRno number, so the +1 rule wakes up: .
  • FATAL = 5 — explicit, teleport back down to 5.

WHY does the +1 rule "resume" after a jump? Because the recurrence in Step 3 never says "add 1 to the previous default" — it says "add 1 to the previous value", whatever that value was, jumped or not. So after WARN=5, the next default is simply .

PICTURE. A number line. Blue explicit landings (1, 5, 5) with teleport arrows; an orange "+1" hop produces ERR = 6.

Figure — Enumerations

Step 5 — Edge case: duplicate values are allowed

WHAT. In Step 4, both WARN and FATAL hold 5. That is completely legal.

WHY it must be legal. The rule only ever produces or copies integers, and integers repeat freely. The language only forbids two tags with the same name — because tags are looked up by name (see Step 7). Two different names can point at the same number, just like two people can live at the same house number.

PICTURE. Two distinct tags WARN and FATAL both pointing at the single value 5.

Figure — Enumerations

Step 6 — Edge case: the trailing COUNT sentinel

WHAT. Put an un-numbered tag last and it automatically equals how many tags came before it:

enum { JAN, FEB, MAR, MONTH_COUNT };  // MONTH_COUNT = 3

WHY it works — chase the recurrence. JAN=0, FEB=1, MAR=2. The trailing tag is just "previous + 1" . But there were exactly 3 real months (JAN, FEB, MAR at positions 0,1,2), so the last value is the count. This is not a special feature — it is Step 3 falling out for free. Add a month and the count updates by itself, which is why it sizes an array safely.

PICTURE. Three data lockers 0,1,2 and a separate green MONTH_COUNT = 3 measuring the whole row like a ruler.

Figure — Enumerations

Step 7 — Degenerate case: at runtime the names vanish

WHAT. After compilation, the tags are gone. Only integers remain. So:

enum Color { RED, GREEN, BLUE };
printf("%d\n", GREEN);   // prints 1, NOT "GREEN"

WHY. The name-tags of Step 1 are a compile-time convenience. The compiler swaps every GREEN for 1 and then throws the tags away. There is no name table left to look up — unlike some languages, C keeps no reverse map. To recover names you must build your own array of strings (an idea linked to Integer Types in C, since the stored thing is a plain int):

const char *names[] = { "RED", "GREEN", "BLUE" };
printf("%s\n", names[GREEN]);  // now prints "GREEN"

PICTURE. Left: compile time, tags visible. Right: runtime, tags peeled off, only bare integers 0 1 2 survive.

Figure — Enumerations

The one-picture summary

Everything above is a single machine: seed with 0, walk with +1, teleport on =, names die at runtime.

Figure — Enumerations
Recall Feynman: retell the whole walkthrough in plain words

Picture a row of lockers. The first one, if you say nothing, gets number 0. Each locker after it copies its left neighbour's number and adds 1 — that's the entire counting rule. If you scribble a number on a locker with =, it jumps to that number, and the next un-numbered locker just keeps adding 1 from there (so 5 becomes 6). Two lockers are allowed to share a number; only the paper name-tags have to be different, because that's how the compiler finds them. A clever trick: an un-numbered tag placed last ends up equal to how many lockers came before, so it counts them for you. And the big secret: once the program actually runs, all the paper tags are peeled off and thrown away — the machine only ever sees the numbers, which is why printing GREEN gives you 1, not the word.


Connections

  • Enumerations — the parent topic this walkthrough derives.
  • Integer Types in C — the enumerator's hidden value is a plain int.
  • switch statement — where these derived values are matched by name.
  • Arrays in C — the COUNT sentinel from Step 6 sizes arrays.
  • struct in C — groups data; enums instead name values.
  • typedeftypedef enum {...} Color; drops the enum keyword.

Concept Map

feeds

falls out as

then

reuses

allows

compiled away

First tag equals 0

Next equals previous plus 1

Explicit equals teleports

Plus one resumes from jump

Duplicate values legal

Trailing COUNT sizes arrays

Names vanish at runtime