41

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

Why is the do while(false) necessary in the macros below?

#define LOG(message, ...) \
do { \
Lock<MutualExclusion> lock (logMutex); \

 .... a lot of code ...
} while (false)

I dont think it serves any functional purpose. Am I overlooking something?

Community
  • 1
  • 1
sivabudh
  • 31,807
  • 63
  • 162
  • 228
  • @Rafe: Of course, macros are pretty gross to begin with. – Fred Larson Jan 12 '11 at 22:02
  • In `C` macros are very helpful. I am currently using macros for generic containers. In `C++` you have templates, you lucky bastards ;-) – gruszczy Jan 12 '11 at 22:05
  • 4
    @Rafe: I'm not sure how this is an abuse of macros. Macros have their place in the C/C++ language. Macros must be structure like this so that they can easily be placed in conditional statements in code. Its standard practice. – Mark Jan 12 '11 at 22:06
  • @Mark but why is this not a function? That's the real question. – Rafe Kettler Jan 12 '11 at 22:08
  • 2
    @Mark: There's no such language as "C/C++", and there's no C tag here. Macros are sometimes necessary in C++, but they are [evil](http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.5). BTW, that link is an excellent answer to this question. – Fred Larson Jan 12 '11 at 22:09
  • 3
    Duplicate: http://stackoverflow.com/questions/154136/why-are-there-sometimes-meaningless-do-while-and-if-else-statements-in-c-c-macr – Éric Malenfant Jan 12 '11 at 22:10
  • @Fred: Mark is right though. I agree that Macros are evil but they are great (well, better than the alternatives) for some jobs and the example in this question is potentially such a case. I do use multi-line macros for code generation sometimes (when templates won’t work) and though I atone for their use through caffeine withdrawal I’m a happier man afterwards. – Konrad Rudolph Jan 12 '11 at 22:15
  • Also, http://stackoverflow.com/questions/2314066/do-whilefalse – gregg Jan 12 '11 at 22:20
  • @Konrad: Yes, I sometimes use macros myself when necessary. I always go through thorough decontamination procedures afterward. ;v) – Fred Larson Jan 12 '11 at 22:20
  • @Fred: I'm not condoning macro use across the board. I'm merely saying that there are cases where they are useful and probably should be used rather than other alternative (i.e. templates in C++). They are rare for sure. I also realize there was no C tag here, but macros are applicable (and useful) in both languages. – Mark Jan 12 '11 at 22:23
  • @Rafe: One example is that I might create an Assert macro to halt execution and give me module and line number information. If that is a function, the assert will trip in the function, merely reporting "Assert tripped in my_assert.cpp at line 15", rather than in the actual code location where the assert was tripped. You can use __FILE__ and __LINE__ in a macro to get the exact location. It might be easy for you or I to find the location at a debugger, but when random artist or designer needs to post a bug, I'd like the exact location of the assert. – Mark Jan 12 '11 at 22:26
  • If there is a lot of code it probably is an overuse of a macro, albeit that a macro for logging can be useful as it can provide __FILE__ and __LINE__ for you, and in testing libraries can also stringify what you are testing which is usually useful. Having done those things they should ideally pass most of these to functions to do. – CashCow Feb 14 '13 at 14:47

7 Answers7

90

It turns a block into a single statement. If you just use a block (i.e. code enclosed in {}) strange things can happen, for example

#define STUFF() \
  { do_something(); do_something_else(); }

if (cond)
    STUFF();
else
    //...

the extra semi-colon breaks the syntax. The do {} while(false) instead is a single statement.

You can find more about this and other macro tricks here.

Giuseppe Ottaviano
  • 4,533
  • 2
  • 18
  • 18
  • 7
    +1 for good answer. Wish I could give another for not being an ass while so many others are. – Edward Strange Jan 12 '11 at 22:40
  • I don't believe this affects the generated code does it? – Alex Pana Jan 12 '15 at 13:36
  • 1
    @AlexPana In debug mode it might (compilers may leave in comparisons that always return true or false for the sake of single-stepping in the debugger having an instruction to land on for that line of code, even though that doesn't really help in this case). Or if the compiler has no optimizations at all. But otherwise, no. – Chiara Coetzee Sep 07 '22 at 18:00
10

So you are forced to add semicolon at the end of the macro, when you use it. This is a common idiom and only way to enforce it.

gruszczy
  • 40,948
  • 31
  • 128
  • 181
7

If somebody has code that does this:

if (something)
    LOG("My log message");

That would expand to:

if (something)
    Lock<MutualExclusion> lock (logMutex);
    // A bunch of other code

Which is incorrect (only the first line would be under the if statement).

The macro makes sure that the macro call is inside of a block of code.

Jacob
  • 77,566
  • 24
  • 149
  • 228
  • 5
    This is half of the story, and could be achieved with just curly braces. The other half of the story is that it won't break in other constructs (the plain curly braces approach would break if used as the only statement in the `if` clause when there is an `else` clause. – David Rodríguez - dribeas Jan 12 '11 at 22:46
  • Good additional information, @David. Thanks. – Jacob Jan 12 '11 at 23:10
4

People use it because otherwise, you can screw up your ifs with compound statements. Imagine

#define hai int x; \
x = 0;

if (condition)
    hai;
else
    func();

Imagine what the preprocessed source looks like.

if (condition)
   int x;
   x = 0;
else
   func();

Oh wait- now our else doesn't work.

Macros like that however are typically unnecessary in C++.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 1
    Even worse, there might not even be a compile error given `if (cond) MACRO; else code;` expanding into `if (cond) if (foo) bar; else code;`. – Fred Nurk Jan 12 '11 at 22:07
2

The reason for this weird practice in #define's is to encapsulate the different assignments within a loop that is executed exactly once, so one may use the macro like a function. For example, with the code you posted, one can write:

if(...)
    LOG(x, y);
else
    // Something else

and it is expanded as

if(...)
    do {...} while(false);
else
    // Something else

This would not work without the do...while(false) surrounding the different assignments, because that would be expanded as

if(...)
    Lock<MutualExclusion> lock (logMutex);

// Other code... Outside the if statement!

Also forcing a semicolon after the macro makes it look like a function and you wont get errors because you added an semicolon like after a normal function.

0xHenry
  • 512
  • 3
  • 12
1

It provides local scope to that which is inside the macro.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
1

It looks to me like it is only used for scoping rules, so that Lock<MutualExclusion> falls out of scope at the end of the block.

If that's the reason for it, then it's completely unnecesarry:

// some other code...
string s = "oh hai";
{
  Lock<MutualExclusion> lock(logMutex);
  // MAGIC HAPPENS
}
s = "oh bai";
John Dibling
  • 99,718
  • 31
  • 186
  • 324