enum
C offers us another way to have constant integer values by name: enum
.
For example:
enum {
=1,
ONE=2
TWO};
("%d %d", ONE, TWO); // 1 2 printf
In some ways, it can be better—or different—than using a #define
. Key differences:
enum
s can only be integer types.#define
can define anything at all.enum
s are often shown by their symbolic identifier name in a debugger.#define
d numbers just show as raw numbers which are harder to know the meaning of while debugging.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.
enum
enum
s are automatically numbered unless you override them.
They start at 0
, and autoincrement up from there, by default:
enum {
, // Value is 0
SHEEP, // Value is 1
WHEAT, // Value is 2
WOOD, // Value is 3
BRICK// Value is 4
ORE };
("%d %d\n", SHEEP, BRICK); // 0 3 printf
You can force particular integer values, as we saw earlier:
enum {
=2,
X=18,
Y=-2
Z};
Duplicates are not a problem:
enum {
=2,
X=2,
Y=2
Z};
if values are omitted, numbering continues counting in the positive direction from whichever value was last specified. For example:
enum {
, // 0, default starting value
A, // 1
B=4, // 4, manually set
C, // 5
D, // 6
E=3 // 3, manually set
F, // 4
G// 5
H }
This is perfectly fine, if that’s your style:
enum {
=2,
X=18,
Y=-2, // <-- Trailing comma
Z};
It’s gotten more popular in languages of the recent decades so you might be pleased to see it.
enum
s 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 enum
s to be defined in header files so they can be #include
d at file scope.
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.
enum
is a TypeThis 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 enum
s 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) {
("I'll trade you a brick for two sheep.\n");
printf}
You can also typedef
these, of course, though I personally don’t like to.
typedef enum {
,
SHEEP,
WHEAT,
WOOD,
BRICK
ORE} RESOURCE;
= BRICK; RESOURCE r
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, enum
s are a great way to write nice, scoped, typed, clean code.