It's common practice in C to use:
#define FOO() do { /* body */ } while (0)
While this is fine, it's also possible to do:
#define FOO() { /* body */ }((void)0)
{...}((void)0)
has many of the same benefits: you can't accidentally merge logic, and a ;
is required at the end of the line, so odd expressions like this don't go by un-noticed: FOO() else {...}
.
The only difference I've noticed is it means you need to use braces in if-statements.
if (a)
FOO();
else
BAR();
Must be written as:
if (a) {
FOO();
} else {
BAR();
}
Other then this quirk, it seems to work well, preventing the same kinds of problems do/while
method is typically used for.
Are there any significant differences between the 2 methods?
Said differently, if you see a code-base using {...}((void)0)
, are practical reasons to switch to using do{..}while(0)
, besides the one difference already noted?
A common use of it is for defining the macro body over multiple lines. This improves readability. The while (0) at the end ensures a single iteration and as Robert Love points out in his answer, it ensures that the behavior of the macro is always the same independent of the code surrounding it.
Now, this statement is functionally equivalent to the former. The do ensures the logic inside the curly-brackets executes, the while(0) ensures that happens but once.
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. Now I get it. Thanks for this simplistic explanation.
What is more, this technique lets ourselves define macros outside functions, unlike do-while. On the other hand do ... while (0) is not without cons. For example because this is a loop you can use break and continue instructions within it.
The practical difference is exactly what you pointed out.
The do { ... } while (0)
idiom means that the macro can be used in any context that requires a statement.
Your suggested idiom { ... } ((void)0)
can be used safely in most contexts that require an expression -- but it can fail if it's used in an unbraced if
statement.
I can think of no good reason to use an unfamiliar idiom that almost always works, when there's a well known idiom that always works.
One difference is you can use break with #define FOO() do { /* body */ } while (0)
but not with #define FOO() { /* body */ }(void)0
.
Let's say you are inside a function, say hello()
, and doing something in #define FOO() do { /*some device operation */ } while (0)
but some error occurred so you no longer want to proceed with that device but there are other statements in function hello()
you want to execute, let's say for another device.
So if you use second statement then you will do return most probably which will exit out of hello()
but if you use the first statement you can happily break
and do some operation in same function hello()
for another device.
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