Alternatively, there is the nonstandard compound statement GNU extension which allows to control the “return value” of the macro.
But you should think twice before using this because inline functions are often as fast as macros.
And have been a part of standard C for 20 years (defined in C99).
Perhaps worth noting that the inline keyword of the standard is a suggestion to the compiler – what happens is implementation defined. Usually the compiler knows when to inline, but for time-critical code most have some way to force it (like the __always_inline__ attribute or __forceinline).
So if somebody does foo(x++) this approach will still have a problem.
This particular methodology is not about solving side-effects in macros, but rather to solve the issue of putting multiple statements in a single macro.
do-whiles are pretty neat.
I’ve also used them to encapsulare simple escape logic. Much easier to read and cleaner than using multipe nested if-else statements.