Publications
of Jon Jagger
jon@jaggersoft.com
Appeared in CVu 9.4, May 1997

{ yourself }
#define Just Say NO

The C preprocessor is a very blunt tool. One of its biggest drawbacks is that it does not respect scope. For example, after...
/* cutlery.h */
#define KNIFE (0)
#define FORK  (1)       
#define SPOON (2)
...all following occurences of the token SPOON will be textually substituted with the token 2. The danger is that all really does mean all. Consider this fragment:
/* fubar.h */
#include "cutlery.h"
#include "fishing.h"
The danger is that fishing.h may contain (now or at some later date) this:
#define SPOON (1)
and the fragment will 'expand' to:
#define SPOON (2)
...
#define SPOON (1)
If this happens your compiler will probably generate a warning something like this:
    Warning YOURSELF 3: Redefinition of 'SPOON' is not identical
but it will not generate an error and the compilation will continue.

There is a better way. Instead of writing:

#define KNIFE (0)
#define FORK  (1)
#define SPOON (2)
write, { yourself }, this:
enum cutlery { KNIFE, FORK, SPOON };
This is perfectly legal. SPOON is a fully fledged constant [1]. Now if you write:
enum cutlery { KNIFE, FORK, SPOON };
enum pike_bait { PLUG, SPOON, LURE };
the compiler will issue an error (not a warning) and stop the compilation [2]. The reason is that enum constants live in a single global namespace. Duplicates are simply not permitted.

Now that SPOON has changed from a #defined constant to an enum constant it's as well to remember that changes have a way of rippling out, of touching and affecting and interacting with other code. Will this change interact with anything? It might! Remember that uppercase is traditionally reserved for #defines...

#define SPOON (42)
...
enum cutlery { KNIFE, FORK, SPOON };
Ooops. A change from all uppercase is in order.
enum cutlery { knife, fork, spoon };
As a final added bonus you may now find your debugger is a little more helpful, displaying the token spoon where previously it displayed 2.

That's all for now.
Cheers
Jon Jagger
jon@jaggersoft.com

[1] For example you can happily, legally, safely write int array[SPOON];

[2] Moving a bug to an earlier phase (in this case from debugging to compiling) is always a Good Thing.