cpp.info: Swallowing the Semicolon

Go forward to Duplication of Side Effects
Go backward to Operator Precedence Problems
Go up to Macro Pitfalls
Go to the top op cpp

Swallowing the Semicolon

   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.