Enums in C Explained: Values, a Worked Output Trace and Exam Traps

Learn how C assigns enum values, how explicit resets and duplicate constants behave, and how to trace enum-based switch output without missing fall-through.

KnowledgeGate Team

Exam prep & CS education

Updated 11 Sep 20266 min read

An enum looks like a list of labels, but one output question can combine implicit numbering, an explicit reset, duplicate values and switch fall-through. Memorising only "the first value is zero" fails when numbering begins at 2 or jumps to 7. In the worked trace, implicit numbering gives READY = 3, PAUSED = 8 and phase_score(RUNNING) = 23. Portability, bit flags and common traps require separate checks. The GATE CS Exam Preparation category provides the broader study route.

Enums in C create named integer constants and an enum type

An enumeration groups related names and gives them integer values:

enum Phase { NEW = 2, READY, RUNNING = 7, PAUSED, DONE = 12 };

The tag Phase forms the type name enum Phase. The five enumerators are named integer constants usable in constant expressions and as case labels.

The following declaration creates a variable and initialises it with one of those constants:

enum Phase current = READY;

In C, enum remains part of the type spelling. enum Phase current; is valid, but bare Phase current; needs a typedef. Use an enum when a variable represents one state from a small named domain.

Enum values in C follow the previous value, not the list position

Work from left to right. An explicit initializer sets the current value, and the next unassigned name receives that value plus one.

Enumerator

Reason

Value

NEW

Explicitly set

2

READY

NEW + 1

3

RUNNING

Explicit reset

7

PAUSED

RUNNING + 1

8

DONE

Explicit reset

12

By contrast, enum Rank { BRONZE, SILVER, GOLD }; starts without an initializer, so its values are 0, 1 and 2.

Negative and duplicate values are also allowed:

enum Code { STOP = -2, WAIT, START = 5, RESUME = 5, NEXT };

Here, STOP = -2, WAIT = -1, START = 5, RESUME = 5 and NEXT = 6. The duplicate names remain distinct identifiers. A switch cannot contain both as case labels because both equal 5.

The solving rule is one pass: start at 0 only if the first name has no initializer, propagate every omission as the previous value plus one, and restart from every explicit initializer.

Enum value map for enum Phase: NEW 2, READY 3, RUNNING 7, PAUSED 8, DONE 12, with resets at NEW, RUNNING and DONE.

Worked enum output trace: calculate 3 8 23 step by step

Trace this program without skipping the missing break:

#include <stdio.h>

enum Phase {
    NEW = 2,
    READY,
    RUNNING = 7,
    PAUSED,
    DONE = 12
};

int phase_score(enum Phase p) {
    int total = READY + PAUSED;

    switch (p) {
        case NEW:     total += 1; break;
        case READY:   total += 2; break;
        case RUNNING: total += 4; /* deliberate fall-through */
        case PAUSED:  total += 8; break;
        default:      total += 16;
    }
    return total;
}

int main(void) {
    printf("%d %d %d\n", READY, PAUSED, phase_score(RUNNING));
    return 0;
}

First fill the enum values. READY follows NEW = 2, so READY = 3. PAUSED follows RUNNING = 7, so PAUSED = 8. The first two printed values are therefore 3 and 8.

Inside phase_score, the initial total is:

total = READY + PAUSED = 3 + 8 = 11

The argument is RUNNING, whose value is 7, so control enters case RUNNING. Adding 4 changes the total from 11 to 15. That arm has no break, so execution falls through into case PAUSED even though p is not PAUSED. Adding 8 gives 15 + 8 = 23, and the following break exits the switch. The function returns 23, so the exact output is:

3 8 23
Worked trace of phase_score(RUNNING): 3 plus 8 is 11, RUNNING adds 4 to 15, fall-through to PAUSED adds 8 to 23, output 3 8 23.

Enum variables need validation, and enum storage is not fixed

The names do not make an enum a closed runtime set. enum Phase p = (enum Phase)5; has no matching enumerator. Validate external input with a switch that lists recognised states and rejects everything else in default.

Do not assume sizeof(enum Phase) == 4 or that it equals sizeof(int). The implementation chooses a compatible integer type that represents the declared values. Displaying it as printf("%d", (int)current); makes the conversion explicit.

Use READY because it communicates a state, not because of an assumed byte width. For files, network messages or APIs, define the wire numbers deliberately and validate them instead of copying raw enum object bytes.

Enum, typedef, macros and bit flags solve different problems

A typedef shortens the type spelling:

typedef enum Phase Phase;
Phase next = DONE;

It does not create another enum, duplicate the enumerators or change DONE = 12. A macro such as #define READY 3 is also different. It performs token replacement and provides no enum type grouping. C enumerator names are unscoped within the ordinary identifier namespace, so another enum in the same scope cannot declare another enumerator named READY.

Enums can name individual bits when every value is a power of two:

enum Permission { READ = 1 << 0, WRITE = 1 << 1, EXECUTE = 1 << 2 };
unsigned mask = READ | EXECUTE;

This gives READ = 1, WRITE = 2 and EXECUTE = 4. Therefore mask = 1 | 4 = 5. The test (mask & WRITE) == 0 is true, while (mask & EXECUTE) == 4 is also true. Store combinations in an unsigned mask because 5 combines two permissions rather than naming one permission enumerator. Do not use the sequential Phase values as flags.

Common C enum traps and the correction for each

Trap

What goes wrong

Correction

Assume the first value is 1

An uninitialised first enumerator actually starts at 0

Write the first value before tracing

Count list positions

Explicit resets are ignored

Propagate from the previous value: 2, 3, 7, 8, 12

Reject duplicate values

Valid declarations look invalid

Allow START = 5 and RESUME = 5, but not both as cases in one switch

Skip a missing break

The worked total stops at 15

Continue into case PAUSED to reach 23

Write Phase p without a typedef

Phase is not yet a C type name

Write enum Phase p, or add the typedef

Assume every enum uses four bytes

Code depends on a non-portable size

Treat storage choice as implementation-dependent

Reuse READY in another enum

The identifier collides in the same scope

Choose a distinct enumerator name

A C question normally needs enum Phase unless a typedef exists. It also does not use C++ scoped-enum syntax such as enum class. Apply the rules of the language named in the question.

Enum exam questions test value filling, declarations and control flow

Recurring question forms include filling values after resets, predicting output, finding duplicate case values, choosing a valid C declaration, distinguishing a typedef from an enumerator, testing a bit mask and rejecting a fixed-size assumption. KnowledgeGate currently offers about 3 practice questions on Enums, so treat that as a small practice signal rather than evidence of topic frequency.

Try this rapid check:

enum E { A, B = 4, C, D = 4, F };

The values are A = 0, B = 4, C = 5, D = 4 and F = 5. Therefore C + F = 5 + 5 = 10. A proposed switch containing both case C: and case F: is invalid because both labels equal 5.

After solving the enum logic, use MCQ, MSQ or NAT? GATE Question Types Explained to decide whether the answer is entered as an MCQ, MSQ or NAT response. Do not infer enum frequency or weightage from a three-question practice set; exam-specific claims require the relevant official notification.

Enums in C: the short version and next step

For a reliable trace, write every explicit value, propagate each omitted value as the previous value plus one, mark duplicate numbers, validate values at input boundaries, and follow every switch arm through its break. Here, READY = 3, PAUSED = 8, phase_score(RUNNING) = 23, and READ | EXECUTE = 5. For a structured route through C declarations, control flow, functions, structures and practice, use the C Language Course: Concepts, MCQs and Coding. Or change RUNNING = 7 to RUNNING = 9: PAUSED becomes 10, and 3 + 10 + 4 + 8 = 25, so the output becomes 3 10 25.