tags:

views:

187

answers:

8
+1  Q: 

#define or enum?

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

+4  A: 

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

Daniel Băluţă
+7  A: 

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
+2  A: 

#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
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*.
AndreyT
regardless, if possible enums are preferable because they're type-safe and don't overwrite any other code
Nathan Fellman
@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`.
AndreyT
@Andrey: Good catch, for some reason I assumed C++ was the intended platform here.
MikeD
@Andrey, why would you recommend #define so strongly? What disadvantages does enum have?
Nathan Fellman
@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.
AndreyT
+2  A: 

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
+5  A: 

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.

AndreyT
Most compilers allow you to specify the size of enums.
Adam Shiemke
@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.
AndreyT
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
@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`.
AndreyT
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
@Adam: I don't think **gcc** does what you believe.
Joseph Quinsey
A: 

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
yes you can: `enum (a = 1, b = 2, c = 4, d = 5)`
Nathan Fellman
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.
AndreyT
Sure you can! `enum Color { default = 0x0, red = 0x1, blue = 0x2 };` and later `paint_square(red | blue)`
Mecki
Well, I know you can set values to enum items like that, but isn't using them this way kind of... non-traditional?
che
@AndreyT: With gcc, enums _are_ unsigned, unless you specify a negative value.
Joseph Quinsey
@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`.
AndreyT
Just checked... Indeed GCC treats enums as unsigned even in C99 mode. A *HUGE* bug in GCC compiler.
AndreyT
@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
@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.
AndreyT
+3  A: 

Technically it doesn't matter. The compiler will most likely even create identical machine code for either case, but an enumeration has two 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. 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.

Mecki
Good answer... +1
wrapperm
A: 

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