enum
A data type that groups related constants under meaningful names. Instead of using plain integers for things like days of the week, directions, or status codes, an enum lets you represent a limited set of values with descriptive names, improving code readability.
Syntax
// Defines an enumeration (values are assigned starting from 0, 1, 2 ...).
enum tag_name {
CONSTANT_1,
CONSTANT_2,
CONSTANT_3
};
// You can explicitly assign values.
enum tag_name {
CONSTANT_1 = value1,
CONSTANT_2 = value2,
CONSTANT_3 // Assigned the previous value + 1.
};
// Declares an enum variable.
enum tag_name variable_name;
enum tag_name variable_name = CONSTANT;
// Combined with typedef, you can omit the enum keyword.
typedef enum { CONSTANT_1, CONSTANT_2 } TypeName;
Characteristics of Enumerations
| Feature | Description |
|---|---|
| Default values | The first constant starts at 0 and increments by 1. If you assign a value at any position, the sequence continues from there. |
| Internal representation | Enum constants are treated as integers (int) internally. Conversion between enums and integers is implicit. |
| Scope | In C, enum constants are placed in the global scope. It is common practice to use a prefix to avoid name collisions. |
| Use with switch | Because enum values are integers, combining them with a switch statement to branch logic for each state is a common pattern. |
Sample Code
sample_enum.c
#include <stdio.h>
/* Days of the week (MON = 0, TUE = 1, ...). */
typedef enum {
MON, TUE, WED, THU, FRI, SAT, SUN
} Weekday;
typedef enum {
DIR_NORTH = 0,
DIR_EAST = 1,
DIR_SOUTH = 2,
DIR_WEST = 3
} Direction;
typedef enum {
ERR_OK = 0,
ERR_NOTFOUND = -1,
ERR_DENIED = -2,
ERR_TIMEOUT = -3
} ErrorCode;
void print_weekday(Weekday day) {
const char *names[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
printf("Day: %s\n", names[day]);
}
const char *direction_name(Direction d) {
switch (d) {
case DIR_NORTH: return "North";
case DIR_EAST: return "East";
case DIR_SOUTH: return "South";
case DIR_WEST: return "West";
default: return "Unknown";
}
}
int main(void) {
Weekday today = WED;
print_weekday(today);
/* Enum values behave as integers. */
printf("Value of WED: %d\n", WED);
Direction dir = DIR_NORTH;
printf("Direction: %s\n", direction_name(dir));
ErrorCode err = ERR_NOTFOUND;
switch (err) {
case ERR_OK: printf("Success\n"); break;
case ERR_NOTFOUND: printf("Not found.\n"); break;
case ERR_DENIED: printf("Access denied.\n"); break;
case ERR_TIMEOUT: printf("Timed out.\n"); break;
}
printf("Size of Weekday: %zu bytes\n", sizeof(Weekday));
return 0;
}
Run the following command:
gcc enum.c -o enum ./enum Day: Wed Value of WED: 2 Direction: North Not found. Size of Weekday: 4 bytes
Managing Game State with enum
Using enum to manage game or application states (e.g., title, playing, paused, game over) avoids magic numbers and makes code self-documenting.
enum_game_state.c
#include <stdio.h>
typedef enum {
STATE_TITLE,
STATE_PLAYING,
STATE_PAUSED,
STATE_GAME_OVER,
STATE_COUNT /* sentinel: automatically holds the total count */
} GameState;
const char *state_name(GameState s) {
const char *names[STATE_COUNT] = {
"Title", "Playing", "Paused", "Game Over"
};
return (s < STATE_COUNT) ? names[s] : "Unknown";
}
void transition(GameState *current, GameState next) {
printf("%s → %s\n", state_name(*current), state_name(next));
*current = next;
}
int main(void) {
GameState state = STATE_TITLE;
printf("Total states: %d\n", STATE_COUNT);
transition(&state, STATE_PLAYING);
transition(&state, STATE_PAUSED);
transition(&state, STATE_PLAYING);
transition(&state, STATE_GAME_OVER);
return 0;
}
Compile and run with the following command:
gcc enum_game_state.c -o enum_game_state ./enum_game_state Total states: 4 Title → Playing Playing → Paused Paused → Playing Playing → Game Over
Common Mistakes
Common Mistake: Name Collision Between Different Enums
In C, enum constant names are placed in the global scope. Using the same name in two different enums causes a compile error. Use prefixes to separate name spaces.
enum_naming_ng.c
#include <stdio.h>
/* NG: without prefixes, NORTH collides in both enums */
/* typedef enum { NORTH, EAST, SOUTH, WEST } Direction; */
/* typedef enum { NORTH, SOUTH } Axis; */ /* NORTH already defined — compile error */
/* OK: use a prefix per enum */
typedef enum {
DIR_NORTH, DIR_EAST, DIR_SOUTH, DIR_WEST
} Direction;
typedef enum {
AXIS_NORTH, AXIS_SOUTH
} Axis;
int main(void) {
Direction d = DIR_NORTH;
Axis a = AXIS_SOUTH;
printf("Direction: %d\n", d); /* 0 */
printf("Axis: %d\n", a); /* 1 */
return 0;
}
Run the following command:
gcc enum_naming_ng.c -o enum_naming_ng ./enum_naming_ng Direction: 0 Axis: 1
Notes
Enumerations improve readability, but they are integers under the hood. C's type checking for enums is loose — a compiler may not warn you if you accidentally assign a value from a different enum type. Because enum constant names live in the global scope, using the same name in two different enums causes a compile error. Use prefixes (e.g., "DIR_", "ERR_") to avoid collisions.
When combining enums with switch, some compilers can be configured to warn about unhandled enum constants. Enabling this warning helps you catch missing cases when you add new constants.
Use enumerations for groups of related constants. To group data of different types together, use struct. For type aliases, see typedef.
If you find any errors or copyright issues, please contact us.