The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

C Preprocessor

20 years of programming C and I still don't understand the preprocessor.

#if TARGET_WINDOWS /* assume TARGET_WINDOWS is 1 for this example */
typedef enum {
} WinFlags;

void routine(WinFlags flag)
  switch(flag) {
    case WINDOWS_FLAG_A: /* this compiles fine - WINDOWS_FLAG_A  is defined */
    case WINDOWS_FLAG_B:
  doStuffWin(); /* this isn't included - WINDOWS_FLAG_A is NOT defined */

So why is the constant defined in part of the code and not in others?
Dennis Atkins
Friday, November 12, 2004
I think you are confusing

#define BLAH


enum {

They aren't the same.  One is a compiler define which will work with #if but the other will not.
Zekaric Send private email
Friday, November 12, 2004
It appears that WINDOWS_FLAG_A is not a macro.

That is, it's something like:

external int WINDOWS_FLAG_A;

This means it will compile but not be a defined macro (i.e. "#ifdef WINDOWS_FLAG_A" will be false).
(someone else)
Friday, November 12, 2004
Thanks - I guess it does have to do with it being an enum. In my leaky abstraction, I have always considered an enum to be a form of typed #define grouping.

In the ANSI C grammar we have:

  # if constant-expression
  # ifdef identifier
  # ifndef identifier

Now, a constant-expression can include a 'enumeration-constant'. But is an enumeration-constant also an identifier?

The grammar starts out with "the grammar has undefined terminal symbols ... identifier .... and enumeration-constant". So I guess technically could it be up to the compiler?
Dennis Atkins
Friday, November 12, 2004
OK, did some tests. The ANSI C grammar suggests that an enum should work with #if but possibly not with #ifdef. However, testing this, the enum does not work with #if either. Tried compiling as C and C++ to see if it was one of those differences between the way the two handle enums but that wasn't it either.

Given the grammar, it seems like it should work for #if, right?
Dennis Atkins
Friday, November 12, 2004
Do you mean the ANSI C Standard? I don't have a copy of that document; could you quote the bit of it that suggests what you're talking about?
Friday, November 12, 2004
It's the grammar rules and commentary I quoted already; section A13.
Dennis Atkins
Friday, November 12, 2004
And actually:

  enum identifier {enumerator-list}

  enumerator-list, enumerator

  identifier = constant-expression

So the grammar specifies enumerators made up of identifiers also...
Dennis Atkins
Friday, November 12, 2004

A12.5 says that during macro expansion of preprocessor conditionals, "The resulting constant expression is restricted: it must be integral, and may not contain sizeof, a cast, or an enumeration constant."

So there you have it. Thanks everybody!
Dennis Atkins
Friday, November 12, 2004
Another way of looking at things is to consider that, especially on Unix systems, the C preprocessor is often a separate program invoked as part of the C compiler, but before the compiler proper, and the preprocessor is used to process more than C programs.

e.g. on many systems, /lib/cpp is the preprocessor.

For a while, GCC had a program called "cccp" (C-compatible C preprocessor) that it invoked before "cc1" and "cc2".  Today, the preprocessor is integrated into the compiler.

X11 has a portable makefile system called "Imake" with the feature that the MAKEFILES are preprocessed using the C preprocessor.

The upshot of all this: any symbol that is given a value through C language semantics (such as an enumeration constant) is given said value AFTER the preprocessor has run, so the preprocessor can't do anything with it.  The only items that the preprocessor can use in an expression are constants, and macros that have previously been defined with #define.
David Jones Send private email
Saturday, November 13, 2004
Yet another way of looking at it is that using the preprocessor is really a terrible way to program.

    Flava Flav!
Flava Flav
Saturday, November 13, 2004
I find that the preprocessor's ability to include header files is really useful but you are right, I am probably just lazy and undisciplined.
Roderick Flamingo
Sunday, November 14, 2004
"the preprocessor is really a terrible way to program."

True, but completely unavoidable for some things and in some environments...
Sunday, November 14, 2004

To reinforce what others have said above, the C preprocessor IS a separate program from the compiler. It takes a source file (usually C code but doesn't have to be), applies textual processing to it, and the output text is passed to the compiler.

This concept of separate textual processing is absolutely inherent in the C (and C++) language, regardless of what you might try to read into the grammar.

The C preprocessor knows about C lexical tokens in the source file, but it knows nothing about the C language beyond that.

So #ifdef can test things that are previously #define'd and nothing else. #if can test things that are previously #defined, or integer constants, or expressions involving both, and that is the limit of it. At no point is there ever any relationship between a symbol (macro) which is #define'd and a symbol that is an enumerated constant. The former is known only to the preprocessor and the latter is known only to the compiler.

The C preprocessor is in fact its own "language" with its own grammar. (One way this becomes apparent is the need to use a backslash for continuation of lines in the preprocessor. The preprocessor sees a file as a sequence of lines separated by newline characters, whereas the compiler sees the file as a sequence of tokens wherein newlines are just another whitespace character like space or tab.)
Ian Boys Send private email
Monday, November 15, 2004
"I find that the preprocessor's ability to include header files is really useful but you are right, I am probably just lazy and undisciplined."

If only Bjarne had gone with the include directive.... *sigh*
Mr Jack
Tuesday, November 16, 2004

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
Powered by FogBugz