C Enums

Creating named constants for better code

🏷️ What are C Enums?

Enumerations in C allow you to create named integer constants, making your code more readable and maintainable by replacing magic numbers with meaningful names.


// Enum for days of week
enum Day {
    MONDAY, TUESDAY, WEDNESDAY
};
                                    

Enum Features

🔢

Named Constants

Replace magic numbers

enum Status {
    SUCCESS, ERROR
};
📊

Auto Numbering

Automatic integer assignment

// RED=0, GREEN=1, BLUE=2
enum Color {RED, GREEN, BLUE};
🎯

Custom Values

Assign specific values

enum Grade {
    A = 90, B = 80, C = 70
};
📖

Readability

Self-documenting code

if (status == SUCCESS) {
    // Clear meaning
}

🔹 Basic Enum Example

Enumerations (enums) in C provide a way to create named integer constants, making code more readable and maintainable. The enum keyword defines a set of related constants, such as enum Color {RED, GREEN, BLUE}; which automatically assigns values starting from 0. Enums improve code clarity by replacing magic numbers with meaningful names, making your intention explicit. For example, instead of using if(status == 2), you can write if(status == ACTIVE) which clearly communicates the program's logic. Enums are particularly useful for representing states, options, error codes, and any scenario where you have a fixed set of related constant values throughout your application.

#include <stdio.h>

enum Day {
    SUNDAY,    // 0
    MONDAY,    // 1
    TUESDAY,   // 2
    WEDNESDAY, // 3
    THURSDAY,  // 4
    FRIDAY,    // 5
    SATURDAY   // 6
};

int main() {
    enum Day today = WEDNESDAY;
    enum Day weekend = SATURDAY;
    
    printf("Today is day number: %d\n", today);
    printf("Weekend starts on day: %d\n", weekend);
    
    // Using enum in conditions
    if (today == WEDNESDAY) {
        printf("It's Wednesday - Hump day!\n");
    }
    
    // Loop through all days
    printf("\nDays of the week:\n");
    for (enum Day d = SUNDAY; d <= SATURDAY; d++) {
        printf("Day %d: ", d);
        switch(d) {
            case SUNDAY:    printf("Sunday\n"); break;
            case MONDAY:    printf("Monday\n"); break;
            case TUESDAY:   printf("Tuesday\n"); break;
            case WEDNESDAY: printf("Wednesday\n"); break;
            case THURSDAY:  printf("Thursday\n"); break;
            case FRIDAY:    printf("Friday\n"); break;
            case SATURDAY:  printf("Saturday\n"); break;
        }
    }
    
    return 0;
}

Output:

Today is day number: 3
Weekend starts on day: 6
It's Wednesday - Hump day!

Days of the week:
Day 0: Sunday
Day 1: Monday
Day 2: Tuesday
Day 3: Wednesday
Day 4: Thursday
Day 5: Friday
Day 6: Saturday

🔹 Enum with Custom Values

C allows you to assign specific integer values to enum constants, giving you precise control over their numeric representations. By default, enum values start at 0 and increment by 1, but you can override this with explicit assignments like enum Status {PENDING = 100, APPROVED = 200, REJECTED = 300}; This feature is invaluable when working with external systems, APIs, or protocols that require specific numeric codes. You can also set only some values explicitly, and the compiler will continue incrementing from that point. Custom enum values ensure compatibility with existing codebases, database schemas, or communication protocols where specific numeric identifiers must be maintained for consistency.

#include <stdio.h>

enum HTTPStatus {
    OK = 200,
    NOT_FOUND = 404,
    SERVER_ERROR = 500,
    BAD_REQUEST = 400
};

enum Priority {
    LOW = 1,
    MEDIUM = 5,
    HIGH = 10,
    CRITICAL = 20
};

int main() {
    enum HTTPStatus response = NOT_FOUND;
    enum Priority taskPriority = HIGH;
    
    printf("HTTP Response Code: %d\n", response);
    printf("Task Priority Level: %d\n", taskPriority);
    
    // Using enums in switch statements
    switch(response) {
        case OK:
            printf("Request successful!\n");
            break;
        case NOT_FOUND:
            printf("Page not found!\n");
            break;
        case SERVER_ERROR:
            printf("Server error occurred!\n");
            break;
        case BAD_REQUEST:
            printf("Bad request!\n");
            break;
        default:
            printf("Unknown status code\n");
    }
    
    // Priority comparison
    if (taskPriority >= HIGH) {
        printf("This is a high priority task!\n");
    }
    
    return 0;
}

Output:

HTTP Response Code: 404
Task Priority Level: 10
Page not found!
This is a high priority task!

🔹 Enum in Structures

Combining enums with structures creates powerful and self-documenting data types that represent complex real-world entities. You can declare enum members within structures like struct Employee {char name[50]; enum Department dept; int salary;}; where the enum clearly defines valid department values. This approach enforces type safety and makes the code intention obvious to other developers. Using enums as structure members is common in modeling objects with categorical properties, such as employee records, product types, vehicle classifications, or user roles. The combination provides both the organizational benefits of structures and the clarity of named constants, resulting in more maintainable and error-resistant code.

#include <stdio.h>
#include <string.h>

enum Gender {
    MALE,
    FEMALE,
    OTHER
};

enum MaritalStatus {
    SINGLE,
    MARRIED,
    DIVORCED,
    WIDOWED
};

struct Person {
    char name[50];
    int age;
    enum Gender gender;
    enum MaritalStatus status;
};

const char* getGenderString(enum Gender g) {
    switch(g) {
        case MALE: return "Male";
        case FEMALE: return "Female";
        case OTHER: return "Other";
        default: return "Unknown";
    }
}

const char* getStatusString(enum MaritalStatus s) {
    switch(s) {
        case SINGLE: return "Single";
        case MARRIED: return "Married";
        case DIVORCED: return "Divorced";
        case WIDOWED: return "Widowed";
        default: return "Unknown";
    }
}

int main() {
    struct Person people[3] = {
        {"Alice Johnson", 28, FEMALE, SINGLE},
        {"Bob Smith", 35, MALE, MARRIED},
        {"Charlie Brown", 42, MALE, DIVORCED}
    };
    
    printf("Person Database:\n");
    printf("================\n");
    
    for(int i = 0; i < 3; i++) {
        printf("%d. %s\n", i+1, people[i].name);
        printf("   Age: %d\n", people[i].age);
        printf("   Gender: %s\n", getGenderString(people[i].gender));
        printf("   Status: %s\n", getStatusString(people[i].status));
        printf("\n");
    }
    
    return 0;
}

Output:

Person Database:
================
1. Alice Johnson
   Age: 28
   Gender: Female
   Status: Single

2. Bob Smith
   Age: 35
   Gender: Male
   Status: Married

3. Charlie Brown
   Age: 42
   Gender: Male
   Status: Divorced

🔹 Enum for State Machine

Enumerations are ideal for implementing state machines, which are fundamental patterns in software design for managing program flow and behavior. A state machine uses an enum like enum State {IDLE, RUNNING, PAUSED, STOPPED}; to represent different operational states clearly. You can then use switch statements to handle state transitions and execute appropriate actions based on the current state. This pattern is widely used in game development, protocol implementations, UI management, and embedded systems. State machines with enums make complex control logic more manageable, easier to debug, and simpler to extend with new states without cluttering the code with arbitrary numeric constants.

#include <stdio.h>

enum TrafficLight {
    RED,
    YELLOW,
    GREEN
};

enum TrafficLight nextState(enum TrafficLight current) {
    switch(current) {
        case RED:
            return GREEN;
        case GREEN:
            return YELLOW;
        case YELLOW:
            return RED;
        default:
            return RED;
    }
}

const char* getLightName(enum TrafficLight light) {
    switch(light) {
        case RED: return "RED";
        case YELLOW: return "YELLOW";
        case GREEN: return "GREEN";
        default: return "UNKNOWN";
    }
}

const char* getAction(enum TrafficLight light) {
    switch(light) {
        case RED: return "STOP";
        case YELLOW: return "CAUTION";
        case GREEN: return "GO";
        default: return "ERROR";
    }
}

int main() {
    enum TrafficLight light = RED;
    
    printf("Traffic Light Simulation:\n");
    printf("========================\n");
    
    for(int i = 0; i < 6; i++) {
        printf("Light: %s - Action: %s\n", 
               getLightName(light), getAction(light));
        light = nextState(light);
    }
    
    return 0;
}

Output:

Traffic Light Simulation:
========================
Light: RED - Action: STOP
Light: GREEN - Action: GO
Light: YELLOW - Action: CAUTION
Light: RED - Action: STOP
Light: GREEN - Action: GO
Light: YELLOW - Action: CAUTION

🧠 Test Your Knowledge

What is the default value of the first enum constant?