Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Comments on What is do { } while(0) in macros and should we use it?
Parent
What is do { } while(0) in macros and should we use it?
Background
I can see the need to use { }
when implementing a function-like macro such as this one:
#define HCF(code) fprintf(stderr, "halt and catch fire"); exit(code);
Because if we use the following calling code
bool bad = false;
if(bad)
HCF(0xDEADBEEF);
printf("good");
Then it will expand to
bool bad = false;
if(bad)
fprintf(stderr, "halt and catch fire");
exit(0xDEADBEEF);
printf("good");
which was not the intention - it will now exit with an error code even though the program is working as intended.
So the correct way would be to write the macro like this instead:
#define HCF(code) { fprintf(stderr, "halt and catch fire"); exit(code); }
Question
But I've come across macros that instead of just plain braces { }
uses this:
#define HCF(code) do { fprintf(stderr, "halt and catch fire"); \
exit(code); } while(0)
This seems similar to { }
but more obscure. What's the purpose of this do { } while(0)
and why should it be used instead of { }
?
Post
Reasons to use the construct #define FOO(x) do{...} while(0);
:
-
As mentioned above, doing so solves the problem of
if (...) FOO(y);
-
You can declare variables inside the block, and they harmlessly go out of scope at the end of the block. Without the
do{}
block, the same symbol would cause a warning (or worse) if it were declared elsewhere in the block in whichFOO(x)
gets expanded.Why declare variables inside a macro? In case a macro argument appears more than once in the body, and someone writes
FOO(func(y))
, wherefunc
has side effects. This includesFOO(y++)
etc. After the macro expands, the side effect would happen as many times as the macro argument appears in the body!Declaring a variable inside a do {} block prevents this, as follows:
#define FOO(x) do { long xx = x; func2(xx); func3(xx); } while (0);
Obviously there is still an assumption about type of
x
, but that is the case anyway if you are going to be callingfunc2(x)
etc. -
Without the
do{}
block, there might be ambiguity as to whetherFOO(x)
expands into a statement or an expression.do{}
makes it clearly a statement, which can help catch someone trying to useFOO(x)
where an expression is expected. See also: "statement-expressions", aka({...})
, which is a construct in case you want the block to be an expression rather than a statement.
0 comment threads