Macros are copy/pasted pieces of text the pre-processor will put in the genuine code; the macro's author hopes the replacement will produce valid code.
There are three good "tips" to succeed in that:
Help the macro behave like genuine code
Normal code is usually ended by a semi-colon. Should the user view code not needing one...
doSomething(1) ; DO_SOMETHING_ELSE(2) // <== Hey? What's this? doSomethingElseAgain(3) ;
This means the user expects the compiler to produce an error if the semi-colon is absent.
But the real real good reason is that at some time, the macro's author will perhaps need to replace the macro with a genuine function (perhaps inlined). So the macro should really behave like one.
So we should have a macro needing semi-colon.
Produce a valid code
As shown in jfm3's answer, sometimes the macro contains more than one instruction. And if the macro is used inside a if statement, this will be problematic:
if(bIsOk) MY_MACRO(42) ;
This macro could be expanded as:
#define MY_MACRO(x) f(x) ; g(x) if(bIsOk) f(42) ; g(42) ; // was MY_MACRO(42) ;
The g function will be executed regardless of the value of bIsOk.
This means that we must have to add a scope to the macro:
#define MY_MACRO(x) { f(x) ; g(x) ; } if(bIsOk) { f(42) ; g(42) ; } ; // was MY_MACRO(42) ;
Produce a valid code 2
If the macro is something like:
#define MY_MACRO(x) int i = x + 1 ; f(i) ;
We could have another problem in the following code:
void doSomething() { int i = 25 ; MY_MACRO(32) ; }
Because it would expand as:
void doSomething() { int i = 25 ; int i = 32 + 1 ; f(i) ; ; // was MY_MACRO(32) ; }
This code won't compile, of course. So, again, the solution is using a scope:
#define MY_MACRO(x) { int i = x + 1 ; f(i) ; } void doSomething() { int i = 25 ; { int i = 32 + 1 ; f(i) ; } ; // was MY_MACRO(32) ; }
The code behaves correctly again.
Combining semi-colon + scope effects?
There is one C/C++ idiom that produces this effect: The do/while loop:
do { // code } while(false) ;
The do/while can create a scope, thus encapsulating the macro's code, and needs a semi-colon in the end, thus expanding into code needing one.
The bonus?
The C++ compiler will optimize away the do/while loop, as the fact its post-condition is false is known at compile time. This means that a macro like:
#define MY_MACRO(x) \ do \ { \ const int i = x + 1 ; \ f(i) ; g(i) ; \ } \ while(false) void doSomething(bool bIsOk) { int i = 25 ; if(bIsOk) MY_MACRO(42) ; // Etc. }
will expand correctly as
void doSomething(bool bIsOk) { int i = 25 ; if(bIsOk) do { const int i = 42 + 1 ; // was MY_MACRO(42) ; f(i) ; g(i) ; } while(false) ; // Etc. }
and is then compiled and optimized away as
void doSomething(bool bIsOk) { int i = 25 ; if(bIsOk) { f(43) ; g(43) ; } // Etc. }
voidtype at the end... like ((void)0).do whileconstruct isn't compatible with return statements, so theif (1) { ... } else ((void)0)construct has more compatible usages in Standard C. And in GNU C, you'll prefer the construct described in my answer.