Next: Duplication of Side Effects, Previous: Operator Precedence Problems, Up: Macro Pitfalls [Contents][Index]
Often it is desirable to define a macro that expands into a compound
statement.  Consider, for example, the following macro, that advances a
pointer (the argument p says where to find it) across whitespace
characters:
#define SKIP_SPACES(p, limit)  \
{ char *lim = (limit);         \
  while (p < lim) {            \
    if (*p++ != ' ') {         \
      p--; break; }}}
Here backslash-newline is used to split the macro definition, which must be a single logical line, so that it resembles the way such code would be laid out if not part of a macro definition.
A call to this macro might be SKIP_SPACES (p, lim).  Strictly
speaking, the call expands to a compound statement, which is a complete
statement with no need for a semicolon to end it.  However, since it
looks like a function call, it minimizes confusion if you can use it
like a function call, writing a semicolon afterward, as in
SKIP_SPACES (p, lim);
This can cause trouble before else statements, because the
semicolon is actually a null statement.  Suppose you write
if (*p != 0) SKIP_SPACES (p, lim); else …
The presence of two statements—the compound statement and a null
statement—in between the if condition and the else
makes invalid C code.
The definition of the macro SKIP_SPACES can be altered to solve
this problem, using a do … while statement.  Here is how:
#define SKIP_SPACES(p, limit)     \
do { char *lim = (limit);         \
     while (p < lim) {            \
       if (*p++ != ' ') {         \
         p--; break; }}}          \
while (0)
Now SKIP_SPACES (p, lim); expands into
do {…} while (0);
which is one statement. The loop executes exactly once; most compilers generate no extra code for it.
Next: Duplication of Side Effects, Previous: Operator Precedence Problems, Up: Macro Pitfalls [Contents][Index]