Prev | Contents | Next

22 Enumerated Types: enum

C offers us another way to have constant integer values by name: enum.

For example:

enum {
  ONE=1,
  TWO=2
};

printf("%d %d", ONE, TWO);  // 1 2

In some ways, it can be better—or different—than using a #define. Key differences:

Since they’re integer types, they can be used any place integers can be used, including in array dimensions and case statements.

Let’s tear into this more.

22.1 Behavior of enum

22.1.1 Numbering

enums are automatically numbered unless you override them.

They start at 0, and autoincrement up from there, by default:

enum {
    SHEEP,  // Value is 0
    WHEAT,  // Value is 1
    WOOD,   // Value is 2
    BRICK,  // Value is 3
    ORE     // Value is 4
};

printf("%d %d\n", SHEEP, BRICK);  // 0 3

You can force particular integer values, as we saw earlier:

enum {
  X=2,
  Y=18,
  Z=-2
};

Duplicates are not a problem:

enum {
  X=2,
  Y=2,
  Z=2
};

if values are omitted, numbering continues counting in the positive direction from whichever value was last specified. For example:

enum {
  A,    // 0, default starting value
  B,    // 1
  C=4,  // 4, manually set
  D,    // 5
  E,    // 6
  F=3   // 3, manually set
  G,    // 4
  H     // 5
}

22.1.2 Trailing Commas

This is perfectly fine, if that’s your style:

enum {
  X=2,
  Y=18,
  Z=-2,   // <-- Trailing comma
};

It’s gotten more popular in languages of the recent decades so you might be pleased to see it.

22.1.3 Scope

enums scope as you’d expect. If at file scope, the whole file can see it. If in a block, it’s local to that block.

It’s really common for enums to be defined in header files so they can be #included at file scope.

22.1.4 Style

As you’ve noticed, it’s common to declare the enum symbols in uppercase (with underscores).

This isn’t a requirement, but is a very, very common idiom.

22.2 Your enum is a Type

This is an important thing to know about enum: they’re a type, analogous to how a struct is a type.

You can give them a tag name so you can refer to the type later and declare variables of that type.

Now, since enums are integer types, why not just use int?

In C, the best reason for this is code clarity–it’s a nice, typed way to describe your thinking in code. C (unlike C++) doesn’t actually enforce any values being in range for a particular enum.

Let’s do an example where we declare a variable r of type enum resource that can hold those values:

// Named enum, type is "enum resource"

enum resource {
    SHEEP,
    WHEAT,
    WOOD,
    BRICK,
    ORE
};

// Declare a variable "r" of type "enum resource"

enum resource r = BRICK;

if (r == BRICK) {
    printf("I'll trade you a brick for two sheep.\n");
}

You can also typedef these, of course, though I personally don’t like to.

typedef enum {
    SHEEP,
    WHEAT,
    WOOD,
    BRICK,
    ORE
} RESOURCE;

RESOURCE r = BRICK;

Another shortcut that’s legal but rare is to declare variables when you declare the enum:

// Declare an enum and some initialized variables of that type:

enum {
    SHEEP,
    WHEAT,
    WOOD,
    BRICK,
    ORE
} r = BRICK, s = WOOD;

You can also give the enum a name so you can use it later, which is probably what you want to do in most cases:

// Declare an enum and some initialized variables of that type:

enum resource {   // <-- type is now "enum resource"
    SHEEP,
    WHEAT,
    WOOD,
    BRICK,
    ORE
} r = BRICK, s = WOOD;

In short, enums are a great way to write nice, scoped, typed, clean code.


Prev | Contents | Next