Multi-Line Macros in C
Every once in a while you need to use a multi-line macro in C. Typically this is because you're doing something like inlining, but for whatever reason inlining isn't particle/portable. I'll first give you the template for doing this correctly, then explain why.
Let's say you want to have a macro run\_and\_test()
and you want it to execute run()
and test()
. The correct form then is this:
#define run_and_test() do { run(); test(); } while(0) /* Note: no ending semi-colon */
Explaination
The beginning C student may start out with something like this:
#define run_and_test() run(); test();
But clearly there's a problem here when used for example in a while loop. A line like this:
while( x-- ) run_and_test()
Will be expanded to:
while(x--) run();
test();
Clearly this is not what we want.
The next thing you might think is to put braces around like so:
#define run_and_test() { run(); test(); }
But this now has a problem in the case of nested if's:
if( condition1 )
if ( condition2 )
run_and_test();
else
something2();
Everything appears okay, doesn't it? However, upon closer inspection, the semi-colon will cause some unintended consequences. The above code expands to:
if( condition1 )
if( condition2 )
{ run(); test(); }; /* this semi-colon breaks things*/
else
something2();
While normally, empty statements in C are valid, the semi-colon after run_and_test();
will now actually be a syntax error. You might argue that you should just use run_and_test()
without a semi-colon. Perhaps even put it in all caps, like RUN_AND_TEST()
to ensure the user is aware of this requirement. However, this special condition is difficult for developers specifically because it is very "un-C-like".
The thing that solves all these conditions, however, is to place the multiple lines in a do { } while(0)
block as shown above. The while(0)
ensures the statement gets executed only once. However, the lack of the semi-colon enforces the typical usage pattern by the developer.
Depending on your macro, the developer may still have to know it's a macro, as there may be side effects, especially if your macro supports arguments. But at least this is one less thing he has to be aware of.