I am confused about when to use macros or enums. Both can be used as constants, but what is the difference between them and what is the advantage of either one? Is it somehow related to compiler level or not?
-
2I think this is a great question when you consider it like this: What are the differences between using macros and enums for defining constants in C? – Sam Harwell Jun 15 '13 at 16:10
7 Answers
In terms of readability, enumerations make better constants than macros, because related values are grouped together. In addition, enum
defines a new type, so the readers of your program would have easier time figuring out what can be passed to the corresponding parameter.
Compare
#define UNKNOWN 0
#define SUNDAY 1
#define MONDAY 2
#define TUESDAY 3
...
#define SATURDAY 7
to
typedef enum {
UNKNOWN,
SUNDAY,
MONDAY,
TUESDAY,
...
SATURDAY,
} Weekday;
It is much easier to read code like this
void calendar_set_weekday(Weekday wd);
than this
void calendar_set_weekday(int wd);
because you know which constants it is OK to pass.

- 3,826
- 5
- 37
- 51

- 714,442
- 84
- 1,110
- 1,523
-
5Indeed, but one could equally stick with the macros, and then `typedef int Weekday;` as neither typedefs nor enums are typesafe (in this sense) in C... – Oliver Charlesworth Jun 15 '13 at 16:14
-
1For me, macros are actually a better choice for debugging. I instantly know which symbolic constant corresponds to a numerical value without having to count all its preceding enum members. – Jun 15 '13 at 16:18
-
8
-
-
Can we change the value of enum at compile time and const is equal to enum or macro – Varun Chhangani Jun 15 '13 at 18:49
-
Also worth noting that if you want to reorder or add a constant in the set, enums automatically update while macros need to be manually recalculated. – Kevin Jun 15 '13 at 18:50
-
2
-
34BTW, it's legal to have a comma after the last item in the enumeration list, so the weird comma formatting isn't necessary. – jamesdlin Jun 15 '13 at 18:57
-
1@H2CO3: Strictly speaking, that's not an advantage of macros over enumerations, since the latter do let you specify the numeric values of elements, if you want, rather than relying on the default numbering. – ruakh Jun 15 '13 at 19:18
-
@ruakh Yes, but that provokes redundancy. I'd rather not write `enum foo { bar = 0, baz = 1, bar = 2, quirk = 3 };` just in order to make stuff easier to debug. – Jun 15 '13 at 19:20
-
1@H2CO3: But you *would* rather scrap enums entirely and use macros plus `typedef int ...` to make stuff easier to debug? De gustibus non est disputandum. – ruakh Jun 15 '13 at 19:22
-
-
1@H2CO3: I don't understand. How did I exaggerate? I just said that this isn't, strictly speaking, an advantage of macros over enums, because enums offer both options. – ruakh Jun 15 '13 at 19:26
-
1@ruakh I was referring to the "But you would rather scrap enums entirely" part. I wouldn't, but I feel there are cases where macros can be more useful regarding *some aspects* in *some cases.* I don't want to say that enums are useless (because they aren't of course), neither should you imply that I do. – Jun 15 '13 at 19:28
-
2@jamesdlin I recently found out it was *not* legal in ANSI C. It surprised me (I always thought the main advantage was that it made code generation that little bit easier) but there you have it. – Thomas Jun 18 '14 at 07:09
-
2@Thomas Hm, interesting. You're right; the grammar for *enum-specifier* in C99 explicitly allows a trailing comma, but the C89 specification does not include that. – jamesdlin Jun 18 '14 at 09:43
A macro is a preprocessor thing, and the compiled code has no idea about the identifiers you create. They have been already replaced by the preprocessor before the code hits the compiler. An enum is a compile time entity, and the compiled code retains full information about the symbol, which is available in the debugger (and other tools).
Prefer enums (when you can).

- 8,779
- 4
- 29
- 57
-
I think that enum is more comfortable compare to macro in case of debugging. – Varun Chhangani Jun 15 '13 at 18:47
-
4Not arguing, but with `gcc -g3`, you can compile a gdb-friendly executable that retains information about macros. – Braden Best Sep 29 '15 at 00:41
In C, it is best to use enums for actual enumerations: when some variable can hold one of multiple values which can be given names. One advantage of enums is that the compiler can perform some checks beyond what the language requires, like that a switch statement on the enum type is not missing one of the cases. The enum identifiers also propagate into the debugging information. In a debugger, you can see the identifier name as the value of an enum variable, rather than just the numeric value.
Enumerations can be used just for the side effect of creating symbolic constants of integral type. For instance:
enum { buffer_size = 4096 }; /* we don't care about the type */
this practice is not that wide spread. For one thing, buffer_size
will be used as an integer and not as an enumerated type. A debugger will not render 4096
into buffer_size
, because that value won't be represented as the enumerated type. If you declare some char array[max_buffer_size];
then sizeof array
will not show up as buffer_size
. In this situation, the enumeration constant disappears at compile time, so it might as well be a macro. And there are disadvantages, like not being able to control its exact type. (There might be some small advantage in some situation where the output of the preprocessing stages of translation is being captured as text. A macro will have turned into 4096, whereas buffer_size
will stay as buffer_size
).
A preprocessor symbol lets us do this:
#define buffer_size 0L /* buffer_size is a long int */
Note that various values from C's <limits.h>
like UINT_MAX
are preprocessor symbols and not enum symbols, with good reasons for that, because those identifiers need to have a precisely determined type. Another advantage of a preprocessor symbol is that we can test for its presence, or even make decisions based on its value:
#if ULONG_MAX > UINT_MAX
/* unsigned long is wider than unsigned int */
#endif
Of course we can test enumerated constants also, but not in such a way that we can change global declarations based on the result.
Enumerations are also ill suited for bitmasks:
enum modem_control { mc_dsr = 0x1, mc_dtr = 0x2, mc_rts = 0x4, ... }
it just doesn't make sense because when the values are combined with a bitwise OR, they produce a value which is outside of the type. Such code causes a headache, too, if it is ever ported to C++, which has (somewhat more) type-safe enumerations.

- 55,781
- 9
- 100
- 149
-
Can we change the value of enum at compile time and const is equal to enum or macro – Varun Chhangani Jun 15 '13 at 18:53
Note there are some differences between macros and enums, and either of these properties may make them (un)suitable as a particular constant.
- enums are signed (compatible with int). In any context where an unsigned type is required (think especially bitwise operations!), enums are out.
- if long long is wider than int, big constants won't fit in an enum.
- The size of an enum is (usually)
sizeof(int)
. For arrays of small values (up to say,CHAR_MAX
) you might want achar foo[]
rather than anenum foo[]
array. - enums are integral numbers. You can't have
enum funny_number { PI=3.14, E=2.71 }
. - enums are a C89 feature; K&R compilers (admittedly ancient) don't understand them.

- 69,818
- 15
- 125
- 179
-
3Actually, the size of enumerations is [*not* guaranteed](http://stackoverflow.com/a/366033/440302) to be the same as `int` although most compilers in practice will use `int` for binary compatibility reasons. – Rufflewind Aug 16 '14 at 08:17
-
1
If macro is implemented properly (i.e it does not suffer from associativity issues when substituted), then there's not much difference in applicability between macro and enum constants in situations where both are applicable, i.e. in situation where you need signed integer constants specifically.
However, in general case macros provide much more flexible functionality. Enums impose a specific type onto your constants: they will have type int
(or, possibly, larger signed integer type), and they will always be signed. With macros you can use constant syntax, suffixes and/or explicit type conversions to produce a constant of any type.
Enums work best when you have a group of tightly associated sequential integer constants. They work especially well when you don't care about the actual values of the constants at all, i.e. when you only care about them having some well-behaved unique values. In all other cases macros are a better choice (or basically the only choice).

- 15,657
- 5
- 63
- 75

- 312,472
- 42
- 525
- 765
As a practical matter, there is little difference. They are equally usable as constants in your programs. Some may prefer one or the other for stylistic reasons, but I can't think of any technical reason to prefer one over the other.
One difference is that macros allow you to control the integral type of related constants. But an enum
will use an int
.
#define X 100L
enum { Y = 100L };
printf("%ld\n", X);
printf("%d\n", Y); /* Y has int type */

- 69,070
- 8
- 110
- 193
-
In C, `enum` constants are always `int`, there is no such rule about wider types. You might be mixing things with C++? – Jens Gustedt Jun 15 '13 at 16:43
-
enum
has an advantage: block scope:
{ enum { E = 12 }; }
{ enum { E = 13 }; }
With macros there is a need to #undef
.

- 5,392
- 4
- 17
- 36
-
I would *never* consider giving an `enum` type different values in different places in the same code base any sort of "advantage" in any way, shape, or form. – Andrew Henle Feb 21 '22 at 12:00
-
If A offers a feature, while B doesn't, then usually A has an advantage over B. – pmor Feb 22 '22 at 18:23
-
You can also drop a bowling ball on your foot. That's not an advantage. – Andrew Henle Feb 22 '22 at 18:27