A C enum lets you replace unexplained integer values with named constants such as MONDAY or STATUS_OK. You can declare an enumeration, assign its constants to variables, and use those constants in conditions and switch statements.
The named enumerators are integer constants, but C provides limited type safety. You should understand both the convenient names and the underlying integer behavior before using C enums in an interface or control-flow operation.
Declare a C enum
An enum declaration defines an enumeration tag and a list of enumerators:
enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY };
Day is the tag, while the names inside the braces are enumerators. This declaration does not create a variable. You can declare one separately:
enum Day today = WEDNESDAY;
You can also declare the variable immediately after the closing brace:
enum Day { MONDAY, TUESDAY, WEDNESDAY } today;
Each enumerator is an integer constant that you can use in initializers, comparisons, array bounds, and case labels. The enumeration type applies to variables such as today; the enumerator names themselves have integer-constant behavior.
C enums: implicit and explicit values
If you omit values, C starts at zero and increases each subsequent value by one. Therefore, MONDAY is 0, TUESDAY is 1, and WEDNESDAY is 2.
You can assign specific values when the numbers have meaning outside your program:
enum HttpStatus { STATUS_OK = 200, STATUS_REDIRECT = 300, STATUS_NOT_FOUND = 404, STATUS_ERROR = 500 };
An unassigned enumerator still follows the previous value. In this example, NORMAL is 2 and URGENT is 11:
enum Priority { LOW = 1, NORMAL, HIGH = 10, URGENT };
Duplicate and nonconsecutive values are allowed. The following names are distinct even though WRITE and MODIFY both represent 2:
enum Permission { READ = 1, WRITE = 2, MODIFY = 2, ADMIN = 8 };
Enumerator names must still be unique within their scope. In standard C, each enumerator has type int. An enum object uses a compatible integer type chosen by the implementation, so its size and signedness can vary.
Use an enum variable with typedef
Without a typedef, you repeat the enum keyword when declaring variables. A typedef gives the enumeration a shorter type name:
typedef enum { MODE_OFF, MODE_IDLE, MODE_RUN } Mode;
Here is a complete, compilable enum variable example:
Standalone source: typedef enum { MODE_OFF, MODE_IDLE, MODE_RUN } Mode; int main(void) { Mode mode = MODE_RUN; return mode == MODE_RUN ? 0 : 1; }
Mode names the enum type, and mode is a variable initialized with the MODE_RUN enumerator. The typedef does not create a separate runtime mechanism; it simply lets you write Mode instead of enum followed by a tag.
C does not strictly restrict an enum variable to its listed enumerators. Because enum types are integer types, an assignment such as mode = 99 is generally permitted, although your compiler may warn about it. The variable can therefore hold a value with no named enumerator.
C enum example: use an enum in a switch
The C enum example below uses named light states in a switch. Each case compares the variable with one enumerator:
Complete source: #include <stdio.h> typedef enum { LIGHT_RED, LIGHT_YELLOW, LIGHT_GREEN } TrafficLight; int main(void) { TrafficLight light = LIGHT_YELLOW; switch (light) { case LIGHT_RED: puts(“Stop”); break; case LIGHT_YELLOW: puts(“Caution”); break; case LIGHT_GREEN: puts(“Go”); break; default: puts(“Unknown light”); break; } return 0; }
The initialized value selects LIGHT_YELLOW, so the program prints Caution. The break statements prevent execution from falling into the next case. Keep the default branch when an enum variable might receive an integer value that is not one of the declared names.
Although duplicate enum values are legal, you cannot use two equal values as separate case labels. For example, case WRITE and case MODIFY would conflict in the Permission enum because both evaluate to 2.
