1

Possible Duplicate:
Why are there sometimes meaningless do/while and if/else statements in C/C++ macros?

In my c code i need to use macro. I compiled my code using gcc. Followings are my experiment:

#define temp(a, b) a++; \
   b++;

foo()
{
  temp(x, y);
}

^^^^^ this will work fine

#define temp(a, b) a++; \
   b++;

foo()
{
  if(z)
     temp(x, y);
  else
    foo();
}

^^^^^ this will not work

#define temp(a, b) { \                                       <<<
   a++; \
   b++; \
   }                                        <<<

foo()
{
   if(z)
     temp(x, y);
   else
     foo();
}

^^^^^ this will also not work

#define temp(a, b)  do { \                                       <<<
   a++; \
   b++; \
   } while(0)                                 <<<

foo()
{
   if(z)
     temp(x, y);
   else
     foo();
}

^^^^^ this will work  :)
Community
  • 1
  • 1
hectk
  • 350
  • 1
  • 3
  • 11

3 Answers3

2

The 'do while' can act as one statement and it's appropriate to terminate it with a ; which is what you wrote after the use of temp.

The other examples don't work because when the macro is expanded, the resulting code has incorrect C++ syntax, or doesn't mean what you intended it to mean.

#define temp(a, b) a++; \
   b++;

foo()
{
  if(z)
     temp(x, y);
  else
    foo();
}

Doesn't work because it expands as:

foo()
{
  if(z)
     x++;
     b++;
  else
    foo();
}

The body of an if or else is only allowed to be one statement in C++, but you essentially put two.

#define temp(a, b) { \
   a++; \
   b++; \
   }

foo()
{
   if(z)
     temp(x, y);
   else
     foo();
}

Expands to:

foo()
{
   if(z)
   {
     a++;
     b++;
   };
   else
     foo();
}

The semi-colon ; before the else isn't allowed there by the language rules. I get the compile error "Illegal else without matching if"

But, the 'do-while' version does work. It expands to:

foo()
{
   if(z)
     do {
       a++;
       b++;
     } while(0);
   else
     foo();
}

Which is perfectly legal C++ and has the behaviour you want. The body of the do-while will be executed exactly once, and as 0 is treated as false and causes execution to leave the loop. The compiler should be able realize that the while condition will always be false and will generate machine instructions that run this efficiently.

Scott Langham
  • 58,735
  • 39
  • 131
  • 204
  • 1
    Incidentally, I generally prefer to have function-ish macros expand as rvalues rather than statements when practical (e.g. `#define foo() (a++, b++)`) since real function calls can be included in rvalues but statements cannot. – supercat Jun 13 '12 at 19:38
0

See here: "What's the best way to write a multi-statement macro?" http://c-faq.com/cpp/multistmt.html

Curd
  • 12,169
  • 3
  • 35
  • 49
0

I wrote a couple of articles covering the preprocessor, including the some of the commonly used folklore, some years ago. The do { ... } while(0) trick is covered in the second part:

https://www.iar.com/knowledge/learn/programming/basics-of-using-the-preprocessor/

https://www.iar.com/knowledge/learn/programming/advanced-preprocessor-tips-and-tricksnew-page/

Lindydancer
  • 25,428
  • 4
  • 49
  • 68