Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expand macro to no code: "do {} while (0)" or "while (0) {}"

In my code I use a macro that should generate a log entry or it should not according to some compilation flag:

#ifdef SOMETHING                                                                
    #define LOG(a)     printf ("%s", a)                                         
#else                                                                           
    #define LOG(a)     while (0) {}                                             
#endif

This code is working fine, but when I look in the Internet, I only see people using

#define LOG(a)     do {} while (0)

instead of

#define LOG(a)     while (0) {}

Are these two approaches equivalent? Should I prefer one over the other?

like image 305
Hobber Avatar asked Jun 18 '26 21:06

Hobber


2 Answers

do {} while (0) and while (0) {} are not equivalent in all contexts, for example, in the latter case the user of the macro will naturally add a syntactically unnecessary semi-colon to the end so that:

if( error )
    LOG( "ERROR") ;
else
{
    ...
}

would expand to:

if( error )
    while(0){} ;
else
{
    ...
}

which fails by disassociating the else from the if because only the while(0){} is conditional.

It should also be noted that neither are syntactically equivalent to the expression printf ("%s", a) which has type int and a better definition is either:

#ifdef SOMETHING                                                                
    #define LOG(a)     do{printf ("%s", a)} while(0)
#else                                                                           
    #define LOG(a)     do{} while(0)
#endif

or

#ifdef SOMETHING                                                                
    #define LOG(a)     printf ("%s", a)                                         
#else                                                                           
    #define LOG(a)     0
#endif

So that LOG() can be used either wherever a statement is valid or wherever an expression is valid. The expression version should be used in circumstances where the value of the expression might be used. The expansion of the expression in a stand-alone statement :

0 ;

is a valid no-op or null statement, but some compilers or static analysers may issue a warning for unused expression.

Common no-op idioms such as :

#define LOG(a)
#define LOG(a) ((void)0)

might also be considered but all suffer from lack of syntactic equivalence to the alternate expansion in the sense that one expansion is valid in all the contexts that the other is valid.

like image 150
Clifford Avatar answered Jun 21 '26 11:06

Clifford


They are different in that

do {} while (0)

needs a semicolon at the end of the statement, while

while (0) {}

does not.

So, when you write

LOG ("Some text\n");

With the first one it expands to

do {} while (0);

which is a single statement, but with the second it expands to

while (0) {};

Which are two statements, the while (0) {} and the ; (which is a valid stament).

This will matter when you combine it with an if. I you write something like:

if (1)
    LOG ("Condition is true\n");
else
    LOG ("Condition is false\n");

with the while (0) {} approach this expands to

if (1)
    while (0) {};
else
    while (0) {};

which is equivalent to

if (1)
    while (0) {}
;
else
    while (0) {}
;

This doesn't compile, since there is an else without a corresponding if.

So, you should prefer the do {} while (0) approach for greater compatibility. Besides, it is more idiomatic.

like image 32
Hobber Avatar answered Jun 21 '26 10:06

Hobber



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!