[prev] [up] [overview] [next]

Section 6. C Preprocessor

6.1: How can I write a generic macro to swap two values?

There is no good answer to this question.  If the values are integers, a well-known trick using exclusive-OR could perhaps be used, but it will not work for floating-point values or pointers, or if the two values are the same variable (and the "obvious" supercompressed implementation for integral types a^=b^=a^=b is in fact illegal due to multiple side-effects; see questions 4.1 and 4.2).  If the macro is intended to be used on values of arbitrary type (the usual goal), it cannot use a temporary, since it does not know what type of temporary it needs, and standard C does not provide a typeof operator.

The best all-around solution is probably to forget about using a macro, unless you're willing to pass in the type as a third argument.

6.2: I have some old code that tries to construct identifiers with a macro like

	#define Paste(a, b) a/**/b

but it doesn't work any more.

That comments disappeared entirely and could therefore be used for token pasting was an undocumented feature of some early preprocessor implementations, notably Reiser's.  ANSI affirms (as did K&R) that comments are replaced with white space. However, since the need for pasting tokens was demonstrated and real, ANSI introduced a well-defined token-pasting operator, ##, which can be used like this:

	#define Paste(a, b) a##b

(See also question 5.4.)

References: ANSI Sec. p. 91, Rationale pp. 66-7.

6.3: What's the best way to write a multi-statement cpp macro?

The usual goal is to write a macro that can be invoked as if it were a single function-call statement.  This means that the "caller" will be supplying the final semicolon, so the macro body should not.  The macro body cannot be a simple brace- delineated compound statement, because syntax errors would result if it were invoked (apparently as a single statement, but with a resultant extra semicolon) as the if branch of an if/else statement with an explicit else clause.

The traditional solution is to use

	#define Func() do { \
		/* declarations */ \
		stmt1; \
		stmt2; \
		/* ... */ \
		} while(0)	/* (no trailing ; ) */

When the "caller" appends a semicolon, this expansion becomes a single statement regardless of context.  (An optimizing compiler will remove any "dead" tests or branches on the constant condition 0, although lint may complain.)

If all of the statements in the intended macro are simple expressions, with no declarations or loops, another technique is to write a single, parenthesized expression using one or more comma operators.  (See the example under question 6.10 below. This technique also allows a value to be "returned.")

References: CT&P Sec. 6.3 pp. 82-3.

6.4: Is it acceptable for one header file to #include another?

It's a question of style, and thus receives considerable debate. Many people believe that "nested #include files" are to be avoided: the prestigious Indian Hill Style Guide (see question 14.3) disparages them; they can make it harder to find relevant definitions; they can lead to multiple-declaration errors if a file is #included twice; and they make manual Makefile maintenance very difficult.  On the other hand, they make it possible to use header files in a modular way (a header file #includes what it needs itself, rather than requiring each #includer to do so, a requirement that can lead to intractable headaches); a tool like grep (or a tags file) makes it easy to find definitions no matter where they are; a popular trick:

	...header file contents...

makes a header file "idempotent" so that it can safely be #included multiple times; and automated Makefile maintenance tools (which are a virtual necessity in large projects anyway) handle dependency generation in the face of nested #include files easily.  See also section 14.

6.5: Does the sizeof operator work in preprocessor #if directives?

No.  Preprocessing happens during an earlier pass of compilation, before type names have been parsed.  Consider using the predefined constants in ANSI's <limits.h>, if applicable, or a "configure" script, instead.  (Better yet, try to write code which is inherently insensitive to type sizes.)

References: ANSI Sec. pp. 6-7, Sec. 3.8.1 p. 87 footnote 83.

6.6: How can I use a preprocessor #if expression to tell if a machine is big-endian or little-endian?

You probably can't.  (Preprocessor arithmetic uses only long ints, and there is no concept of addressing.)  Are you sure you need to know the machine's endianness explicitly?  Usually it's better to write code which doesn't care.

6.7: I've got this tricky processing I want to do at compile time and I can't figure out a way to get cpp to do it.

cpp is not intended as a general-purpose preprocessor.  Rather than forcing it to do something inappropriate, consider writing your own little special-purpose preprocessing tool, instead. You can easily get a utility like make(1) to run it for you automatically.

If you are trying to preprocess something other than C, consider using a general-purpose preprocessor (such as m4).

6.8: I inherited some code which contains far too many #ifdef's for my taste.  How can I preprocess the code to leave only one conditional compilation set, without running it through cpp and expanding all of the #include's and #define's as well?

There are programs floating around called unifdef, rmifdef, and scpp which do exactly this. (See question 17.12.)

6.9: How can I list all of the pre#defined identifiers?

There's no standard way, although it is a frequent need.  If the compiler documentation is unhelpful, the most expedient way is probably to extract printable strings from the compiler or preprocessor executable with something like the Unix strings(1) utility.  Beware that many traditional system-selective pre#defined identifiers (e.g. "unix") are non-Standard (because they clash with the user's namespace) and are being removed or renamed.

6.10: How can I write a cpp macro which takes a variable number of arguments?

One popular trick is to define the macro with a single argument, and call it with a double set of parentheses, which appear to the preprocessor to indicate a single argument:

	#define DEBUG(args) (printf("DEBUG: "), printf args)

	if(n != 0) DEBUG(("n is %d\n", n));

The obvious disadvantage is that the caller must always remember to use the extra parentheses.  Other solutions are to use different macros (DEBUG1, DEBUG2, etc.) depending on the number of arguments, or to play games with commas:

        #define DEBUG(args) (printf("DEBUG: "), printf(args))
        #define _ ,
        DEBUG("i = %d" _ i)
It is often better to use a bona-fide function, which can take a variable number of arguments in a well-defined way.  See questions 7.1 and 7.2.

[prev] [up] [overview] [next]