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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With