Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C multi-line macro: do/while(0) vs scope block [duplicate]

Possible Duplicates:
What’s the use of do while(0) when we define a macro?
Why are there sometimes meaningless do/while and if/else statements in C/C++ macros?
do { … } while (0) what is it good for?

I've seen some multi-line C macros that are wrapped inside a do/while(0) loop like:

 #define FOO \   do { \     do_stuff_here \     do_more_stuff \   } while (0) 

What are the benefits (if any) of writing the code that way as opposed to using a basic block:

 #define FOO \   { \     do_stuff_here \     do_more_stuff \   } 
like image 719
krasnaya Avatar asked Jul 01 '09 04:07

krasnaya


People also ask

Do While Do 0 macros?

You may see a do loop with the conditional expression set to a constant value of zero (0). This creates a loop that will execute exactly one time. This is a coding idiom that allows a multi-line macro to be used anywhere that a single statement can be used.

Why macros use do while?

In conclusion, macros in Linux and other codebases wrap their logic in do/while(0) because it ensures the macro always behaves the same, regardless of how semicolons and curly-brackets are used in the invoking code.

How do you separate a multiline macro in?

"\ operator is used to separate a multiline macro in C language"

Can multi line macros be used?

We can write multiline macros like functions, but for macros, each line must be terminated with backslash '\' character. If we use curly braces '{}' and the macros is ended with '}', then it may generate some error.


1 Answers

Andrey Tarasevich provides the following explanation:

  1. On Google Groups
  2. On bytes.com

[Minor changes to formatting made. Parenthetical annotations added in square brackets []].

The whole idea of using 'do/while' version is to make a macro which will expand into a regular statement, not into a compound statement. This is done in order to make the use of function-style macros uniform with the use of ordinary functions in all contexts.

Consider the following code sketch:

if (<condition>)   foo(a); else   bar(a); 

where foo and bar are ordinary functions. Now imagine that you'd like to replace function foo with a macro of the above nature [named CALL_FUNCS]:

if (<condition>)   CALL_FUNCS(a); else   bar(a); 

Now, if your macro is defined in accordance with the second approach (just { and }) the code will no longer compile, because the 'true' branch of if is now represented by a compound statement. And when you put a ; after this compound statement, you finished the whole if statement, thus orphaning the else branch (hence the compilation error).

One way to correct this problem is to remember not to put ; after macro "invocations":

if (<condition>)   CALL_FUNCS(a) else   bar(a); 

This will compile and work as expected, but this is not uniform. The more elegant solution is to make sure that macro expand into a regular statement, not into a compound one. One way to achieve that is to define the macro as follows:

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

Now this code:

if (<condition>)   CALL_FUNCS(a); else   bar(a); 

will compile without any problems.

However, note the small but important difference between my definition of CALL_FUNCS and the first version in your message. I didn't put a ; after } while (0). Putting a ; at the end of that definition would immediately defeat the entire point of using 'do/while' and make that macro pretty much equivalent to the compound-statement version.

I don't know why the author of the code you quoted in your original message put this ; after while (0). In this form both variants are equivalent. The whole idea behind using 'do/while' version is not to include this final ; into the macro (for the reasons that I explained above).

like image 62
caskey Avatar answered Sep 24 '22 18:09

caskey