22

Possible Duplicate:
Why use enum when #define is just as efficient?

When programming in C, is it better practice to use #define statements or enums for states in a state machine?

Community
  • 1
  • 1
SSS
  • 2,344
  • 8
  • 22
  • 27
  • 6
    The number of questions whose answers are "prefer a `#define`" are surprisingly low. – Stephen Jun 28 '10 at 17:45
  • 1
    @Stephen: Mostly because many posters are locked in C++ mode, while the question is about C. The difference between C and C++ in this regard is rather huge. In fact, in C in most cases you should prefer `#define`, but in this specific case (state machine) `enum` is indeed a better approach. – AnT stands with Russia Jun 28 '10 at 17:57
  • duplicate of something as far as I can remember.Maybe the spec "for states in a state machine", changes it a bit, but there's no reason to consider a "state of state machine" a different application of what #define or enums can be used for... – ShinTakezou Jun 28 '10 at 18:06
  • @AndreyT : Agreed that C++ further lessens the need for `#define`, but since C90 `const` has been a recognized keyword... that kill 99% of uses. This case is (as you mentioned) better to use an `enum`. Using preprocessor symbols can make it much harder to debug. Obviously macros_require `#define`. So, outside of maybe outsmarting the compiler in some cases to concat symbols, what benefits do you see for `#define` constants in c (since C90)? (I should add, maybe to prove your point, that I work in C++) – Stephen Jun 28 '10 at 18:07
  • @Stephen: `const` in C is useless for this purpose. That's actually the difference I was talking about. In C `const` does not produce a *constant*, in C++ it does. In C `const` creates a "const object", which is not a constant and cannot be used where a constant is required. This is why in C you choices are limited to `#define` and `enum`. – AnT stands with Russia Jun 28 '10 at 18:13
  • @AndreyT : Thanks, looks like I got some reading to do. Do you have a pointer to an explanation? The ones I found seem to confirm my (mis)understanding: http://publications.gbdirect.co.uk/c_book/chapter8/const_and_volatile.html or http://yarchive.net/comp/const.html – Stephen Jun 28 '10 at 18:15

9 Answers9

56

Technically it doesn't matter. The compiler will most likely even create identical machine code for either case, but an enumeration has three advantages:

  1. Using the right compiler+debugger combination, the debugger will print enumeration variables by their enumeration name and not by their number. So "StateBlahBlup" reads much nicer than "41", doesn't it?

  2. You don't have explicitly give every state a number, the compiler does the numbering for you if you let it. Let's assume you have already 20 states and you want to add a new state in the middle, in case of defines, you have to do all renumbering on your own. In case of enumeration, you can just add the state and the compiler will renumber all states below this new state for you.

  3. You can tell the compiler to warn you if a switch statement does not handle all the possible enum values, e.g. because you forgot to handle some values or because the enum was extended but you forgot to also update the switch statements handling enum values (it will not warn if there's a default case though, as all values not handled explicitly end up in the default case).

Mecki
  • 125,244
  • 33
  • 244
  • 253
  • 2
    And 4. Unlike the #define, the enum value is represented in the symbol info which means things like GDB can show it / use it in expressions (this is related to point 1). 5. You can #undef the #define and then create another, so it isn't as immutable as an enum. – Andrew Bainbridge May 22 '19 at 10:26
  • 1
    @AndrewBainbridge Immutability is a good point which I never considered so far. I use `#undef` so rarely, that I almost forget it exists but you are right, you can change the value of define. – Mecki May 22 '19 at 19:29
  • Enums also help the IDE with auto-completion, some will generate an entire switch statement for you with all the enum cases. – Trass3r Aug 23 '19 at 14:29
  • Oh and of course auto-generation of enum<->string conversion, via a separate tool or even in-code like this C++ library does: https://github.com/Neargye/magic_enum. – Trass3r Aug 23 '19 at 15:08
13

Since the states are related elements I think is better to have an enum defining them.

Daniel Băluţă
  • 1,255
  • 11
  • 13
9

There's no definitive answer. enum offers you scoping and automatic value assignment, but does not give any control over the constant type (always signed int). #define ignores scoping, but allows you to use better typing facilities: lets you choose the constant type (either by using suffixes or by including an explicit cast into the definition).

So, choose for yourself what is more important to you. For a state machine, enum might be a better choice, unless you have a good reason to control the type.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • Most compilers allow you to specify the size of enums. – Adam Shiemke Jun 28 '10 at 18:12
  • 1
    @Adam Shiemke: ...which is normally a global setting. And I'm talking about the type, not about the size. Neither C nor C++ (in its current form) offer you any meaningful control over the type of enum values. – AnT stands with Russia Jun 28 '10 at 18:17
  • AFAIR C99 offers you no choice for the type of `enum` constants, namely it fixes them to be constants of type `signed int`. An `enum` type itself can have a different width, and it is up to the compiler to choose a convenient size such that fit all constants defined with the type. So in particular you may have that size smaller than for `int` but usually not larger. – Jens Gustedt Jun 28 '10 at 18:27
  • 1
    @Jens Gustedt: When I was referring to typing, I'm mostly talking about the type these values have in expressions, not about the amount of memory these objects occupy. In expressions enum constants are promoted to either `int` or larger. You can't tell the compiler that some enum constant is supposed to act as `unsigned int`, for example, - this is a problem with enum, which is solvable with `#define`. – AnT stands with Russia Jun 28 '10 at 18:33
  • True. I believe gcc will generate warnings if you implicitly cast from one enum to another or any other type. I'm sure CodeWarrior will. But you are correct in general. – Adam Shiemke Jun 28 '10 at 18:46
  • @Adam: I don't think **gcc** does what you believe. – Joseph Quinsey Jun 28 '10 at 22:42
8

I prefer enum. They are more compact and are 'safer'. You can also imply order in an enum, which might be helpful in a state machine. #defines should be avoided if possible, since they will overwrite all occurrences in source, which can lead to some unintended actions which are difficult to debug.

Adam Shiemke
  • 3,734
  • 2
  • 22
  • 23
3

If enum is supported by your compiler, then that would be preferred. Failing that, by all means, use #define. All C++ compilers and modern C compilers should support enum, but older compilers (particularly ones targeting embedded platforms) may not support enum.

If you must use #define make sure to define your constants with parentheses, to avoid preprocessor errors:

#define RED_STATE    (1)
#define YELLOW_STATE (2)
#define GREEN_STATE  (3)
Craig Trader
  • 15,507
  • 6
  • 37
  • 55
2

#define directives can have lots of unintended consequences and don't follow common scoping rules. Use enums when you have related data.

More information: http://www.embedded.com/columns/programmingpointers/9900402?_requestid=341945 [C++ material, but still marginally relevant]

MikeD
  • 3,348
  • 1
  • 23
  • 36
  • The information you linked is about C++, not C. The difference between C and C++ when it comes to choosing a method for defining constants is *HUGE*. – AnT stands with Russia Jun 28 '10 at 17:54
  • regardless, if possible enums are preferable because they're type-safe and don't overwrite any other code – Nathan Fellman Jun 28 '10 at 17:57
  • 1
    @Nathan Fellman: No. In C, `enum` is preferable only when we are working with natural group of constants. In all other cases it is `#define` and only `#define`. – AnT stands with Russia Jun 28 '10 at 18:00
  • @Andrey: Good catch, for some reason I assumed C++ was the intended platform here. – MikeD Jun 28 '10 at 18:05
  • @Andrey, why would you recommend #define so strongly? What disadvantages does enum have? – Nathan Fellman Jun 28 '10 at 20:04
  • @Nathan Fellman: Enums are for declaring logically "grouped" values. I don't see how one can use enum for standalone values (one can, of course, but it will just look ugly). Some other reasons are specified in my answer. – AnT stands with Russia Jun 28 '10 at 20:36
1

You can do this trick to make compiler check the type of #define value.

#define VALUE_NAME ((TYPE_NAME) 12)

However the real problem of #define is it can be redefined in application code. (Of course compiler will warn you about it.)

eonil
  • 83,476
  • 81
  • 317
  • 516
0

enum is great when you have exclusive options, but you can't use them to define bitfield flags, like this:

#define SQ_DEFAULT 0x0
#define SQ_WITH_RED 0x1
#define SQ_WITH_BLUE 0x2

void paint_square(int flags);

Then you can paint red-blue square with:

paint_square(SQ_WITH_RED | SQ_WITH_BLUE);

...which you can't with enum.

che
  • 12,097
  • 7
  • 42
  • 71
  • yes you can: `enum (a = 1, b = 2, c = 4, d = 5)` – Nathan Fellman Jun 28 '10 at 17:59
  • 4
    Can't? Of course, you can: `enum { SQ_DEFAULT = 0x0, SQ_WITH_RED = 0x1, SQ_WITH_BLUE = 0x2 }`. The problem here is that with flags it is better to use an *unsigned* type. But otherwise, enum will work. – AnT stands with Russia Jun 28 '10 at 17:59
  • 1
    Sure you can! `enum Color { default = 0x0, red = 0x1, blue = 0x2 };` and later `paint_square(red | blue)` – Mecki Jun 28 '10 at 17:59
  • Well, I know you can set values to enum items like that, but isn't using them this way kind of... non-traditional? – che Jun 28 '10 at 21:28
  • @AndreyT: With gcc, enums _are_ unsigned, unless you specify a negative value. – Joseph Quinsey Jun 28 '10 at 22:31
  • @Joseph Quinsey: If so, that would be a direct violation of the standard requirements. In C language enum constant always have type `int` and only `int`. – AnT stands with Russia Jun 28 '10 at 22:53
  • Just checked... Indeed GCC treats enums as unsigned even in C99 mode. A *HUGE* bug in GCC compiler. – AnT stands with Russia Jun 28 '10 at 22:58
  • @AndreyT: I haven't checked, but I believe the standard calls for _integral type_. Recent versions of gcc (e.g. within the last decade) will use 64 bits when necessary. But I'm still using 2.95. – Joseph Quinsey Jun 28 '10 at 23:09
  • 2
    @Joseph Quinsey: The standard say that compiler can use any type to *store* enum objects, but the standard is very explicit about the way they must act in *value context*: 6.5.2.2 in C89/90 clearly states that enum constants have type `int`. C99 says the same thing. No variants. GCC is broken in this regard. – AnT stands with Russia Jun 28 '10 at 23:12
0

You can use whatever you want and like.

Still as everyone is saying I would also like add up me as voting for Enums.

Enums should always be preferred if you are using related data as in case of a State Machine, you can define order in enums also that will help in implementing the State Machine.

Further enums will keep your program safe as all enums will be of its type only so they will avoid any possible confusions too.

#define should not be used in case of a state machine or related data. Anyway thats my suggestion, but there is no hard and fast rule.

Also I would like to add up one more point that enums will add more readability and understandability to your code if used in future or or if read by someone else. It is an important point when you are having a very large program and there are a lot of #defines in the program other than you are using for your State Machine.

Kumar Alok
  • 2,512
  • 8
  • 26
  • 36