-1

I come across macros that are defined as follows:

#define CALL_FUNCS(x)
do {
  func1(x);
  func2(x);
  func3(x);
} while (0);

now, of course this will work but how is this any better than the below version ?

#define CALL_FUNCS(x)
{
  func1(x);
  func2(x);
  func3(x);
}

I think it is not about macro optimization. Any thoughts on this ?

mav_2k
  • 171
  • 7
  • The C++ FAQ has [a good entry on this](http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.5) – Seth Carnegie Feb 08 '12 at 20:17
  • Thanks Seth Carnegie, found the pointers: http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.5 – mav_2k Feb 09 '12 at 05:30
  • possible duplicate of [Do-While and if-else statements in C/C++ macros](http://stackoverflow.com/questions/154136/do-while-and-if-else-statements-in-c-c-macros) – legoscia Apr 09 '14 at 17:02

4 Answers4

4

The macro actually should not have the final ;. This is to get normal / more expected and helpful syntax errors around macro if something is wrong.

arsenm
  • 2,903
  • 1
  • 23
  • 23
4

If you don't use the do ... while (0) form in an if-else statement you will get an error:

if (bla) CALL_FUNCS();
else statement;

would be preprocessed as:

if (bla)
{
  func1(x);
  func2(x);
  func3(x);
};
else statement;

The semi-colon before the else statement is invalid.

Note (as pointed out by @arsenm) that you should not put the final ; after the do ... while (0) in the macro definition and you have to and use \ after the lines in the definition:

#define CALL_FUNCS(x)  \
do {                   \
  func1(x);            \
  func2(x);            \
  func3(x);            \
} while (0)
ouah
  • 142,963
  • 15
  • 272
  • 331
  • @SethCarnegie, there are two trailing semicolons to consider. First, there is the incorrect extra semicolon at the end of the *definition* of the macro. But also look at how the macro is used; there is a semicolon in `CALL_FUNCS(x);` which won't disappear even if the second form is used. – Aaron McDaid Feb 08 '12 at 20:24
3

First, it should not have the trailing ;. It should be:

#define CALL_FUNCS(x)    do { func1(x); func2(x); func3(x); } while (0)

Anyway, the reason is as follows. Consider

if(b)
     CALL_FUNCS(x);
else
     something_else(x);

This would expand to:

if(b)
     { func1(x); func2(x); func3(x); };
else
     something_else(x);

Now we still have a trailling ; and will get this error message:

error: ‘else’ without a previous ‘if’

Note, if you keep the ; in the macro, then you will have two trailing ;s!

Macro expansion should 'look' like something that expects a semicolon on the end. You're not going to type CALL_FUNCS(x), you're going to call CALL_FUNCS(x);. You can rely on do.. while(0) to slurp up the semicolon, but { } will not do so.

Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
0

This is used to force the user to add a ; after the macro invocation.

tibur
  • 11,531
  • 2
  • 37
  • 39