C Enums
Introduction to Enumerations
Enumerations (enums) in C are user-defined types whose identifiers (enumerators) stand for integer constant values. Enums let you use meaningful names instead of magic numbers, improving readability and intent.
Important realities in C:
- Enums are integer types chosen by the implementation (not strictly typed like in some other languages).
- You can still assign any integer to an enum variable—so enums do not enforce strict type safety in C.
- Enumerators share the surrounding scope (they are unscoped), so their names must be unique in that scope.
Enum Definition Syntax
Example
enum enum_name {
IDENTIFIER1,
IDENTIFIER2,
IDENTIFIER3
};
ℹ️ Note: By default, the first enumerator has value 0 and each subsequent one increases by 1 unless explicitly assigned.
Enum with Explicit Values
Example
#include <stdio.h>
enum HttpStatus {
HTTP_OK = 200,
HTTP_CREATED = 201,
HTTP_BAD_REQUEST = 400,
HTTP_UNAUTHORIZED = 401,
HTTP_NOT_FOUND = 404,
HTTP_INTERNAL_ERROR = 500
};
enum Priority {
LOW,
MEDIUM,
HIGH = 10,
URGENT, // 11
CRITICAL = 99
};
int main(void) {
printf("HTTP Status Codes:\n");
printf("OK: %d\n", (int)HTTP_OK);
printf("NOT_FOUND: %d\n", (int)HTTP_NOT_FOUND);
printf("\nPriority Levels:\n");
printf("LOW: %d\n", (int)LOW);
printf("HIGH: %d\n", (int)HIGH);
printf("URGENT: %d\n", (int)URGENT);
return 0;
}
Output
HTTP Status Codes: OK: 200 NOT_FOUND: 404 Priority Levels: LOW: 0 HIGH: 10 URGENT: 11
ℹ️ Note: Casting to int in printf is portable because the exact integer type used for the enum is implementation-defined.
Using Enums in Programs
Example
#include <stdio.h>
enum TrafficLight { RED, YELLOW, GREEN };
void handleTrafficLight(enum TrafficLight light) {
switch (light) {
case RED:
printf("Stop! The light is RED.\n");
break;
case YELLOW:
printf("Caution! The light is YELLOW.\n");
break;
case GREEN:
printf("Go! The light is GREEN.\n");
break;
default:
printf("Invalid traffic light state.\n");
}
}
int main(void) {
enum TrafficLight currentLight = GREEN;
handleTrafficLight(currentLight);
currentLight = YELLOW;
handleTrafficLight(currentLight);
currentLight = RED;
handleTrafficLight(currentLight);
return 0;
}
Output
Go! The light is GREEN. Caution! The light is YELLOW. Stop! The light is RED.
Enum with typedef
Example
#include <stdio.h>
typedef enum {
JANUARY = 1,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
AUGUST,
SEPTEMBER,
OCTOBER,
NOVEMBER,
DECEMBER
} Month;
const char* getMonthName(Month month) {
switch (month) {
case JANUARY: return "January";
case FEBRUARY: return "February";
case MARCH: return "March";
case APRIL: return "April";
case MAY: return "May";
case JUNE: return "June";
case JULY: return "July";
case AUGUST: return "August";
case SEPTEMBER: return "September";
case OCTOBER: return "October";
case NOVEMBER: return "November";
case DECEMBER: return "December";
default: return "Invalid Month";
}
}
int main(void) {
Month currentMonth = OCTOBER;
printf("Month %d is %s\n", (int)currentMonth, getMonthName(currentMonth));
printf("Number of days in %s: %d\n", getMonthName(FEBRUARY), 28);
return 0;
}
Output
Month 10 is October Number of days in February: 28
Enum Size and Storage
Example
#include <stdio.h>
enum SmallEnum { A, B, C };
enum LargeEnum { BIG = 1000000, BIGGER };
int main(void) {
printf("Size of SmallEnum: %zu bytes\n", sizeof(enum SmallEnum));
printf("Size of LargeEnum: %zu bytes\n", sizeof(enum LargeEnum));
printf("Size of int: %zu bytes\n", sizeof(int));
int value = (int)BIG; // explicit cast for portability
printf("BIG as integer: %d\n", value);
return 0;
}
ℹ️ Note: The underlying integer type for an enum is implementation-defined; many platforms use the size of int, but it may differ. Use sizeof to check on your platform.
Enum Best Practices
- Use meaningful, UPPER_SNAKE_CASE names for enumerators (e.g., HTTP_NOT_FOUND).
- Avoid reusing enumerator names across different enums in the same scope—enumerators are unscoped in C.
- Consider typedef to avoid writing 'enum' repeatedly and to clarify intent.
- Prefer enums over #define for related integral constants; enumerators are true integer constant expressions (usable in case labels, array sizes, etc.).
- Validate inputs: enums do not prevent arbitrary integers from being assigned—add range checks when needed.