cpp: Swallowing the Semicolon

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