To Do or Not to Do
2015-05-06I was recently in dire need of a hash table implementation in C and wasn’t ready to write one just then. With some luck and after considerable foraging on the internet I came across Troy Hanson’s project, uthash which provides a hash table for C structures.
For some reason, I needed to tweak one of the functions and found uthash to consist entirely of a single header file with macros like this:
#define FOO(stuff) \
do { \
thing1(); \
thing2(); \
} while(0)
It seemed perfectly redundant to have a loop that always executes exactly once. Like most things in the universe, it has a reasonable explanation for its awkwardness.
“It's the only construct in C that you can use to #define a multistatement operation, put a semicolon after, and still use within an if statement.”
For example, if FOO was defined as below:
#define FOO(stuff) thing1(); thing2()
the following if-else construct would be syntactically wrong:
if (condition)
FOO(stuff);
else
other_stuff();
// Preprocessed to:
if (condition)
thing1();
thing2(); => Compiler cries.
else
other_stuff();
Even enclosing the macro body in braces would not help, as you would need to omit the semicolon after the call to FOO, which is counter-intuitive.
#define FOO(stuff) { thing1(); thing2(); }
if (condition)
FOO(x)
else
other_stuff();
The do-while-zero construct makes this syntactically correct:
if (condition)
FOO(x);
else
other_stuff();
On the other hand, you could just use a function and save yourself the brain jitters.