This little piece of seemingly useless C may not seem like a bright idea, but it can be useful when you want to make a macro appear more like a function.

Observe the following example:

	#define FOO() {		\
		foo();		\
		bar();		\
	}

	...

	if( bort )
		FOO();
	else
		bam = bob;

This gets preprocessed as:

	if( bort )
	{
		foo();
		bar();
	};
	else
		bam = bob;

Note semicolon after the end of the block, giving us a glaring parse error! Oh no!

But if we use this weird/clever hack:

	#define FOO()		\
		do {		\
			foo();	\
			bar();	\
		} while(0)

We get:

	if( bort )
		do {
			foo();
			bar();
		} while(0);
	else
		bam = bob;

Which gives us the intended result, and keeps our compiler happy, thus saving the day. Sure, an unnecessary Boolean test is done, but what're you gonna do?

Of course, the problem wouldn't exist in the first place, had we inline functions.

Actually, optimization should eliminate the extra while(0) if the compiler is paying attention. GCC is nice, since it does optimize these things, but of course, GCC allows inline functions too, as long as -O (more precisely, -O3) is given on the command line, and provided you haven't specified -ansi (and even in that case, you can still use __inline__ to identify an inline function).

On the other hand, some less intelligent compilers just do the job of translating into assembly and don't recognize inefficient (or even stupid) code. Maybe this encourages programmers to do more optimizing by hand, but then again, maybe it just shows that those who wrote the compiler didn't have the motivation to add in these spiffy features.

Either way, this is a clever trick, if even nothing more than a workaround solution to the problem of not being able to write whole functions as macros. (That, in itself, may be looked at as a problem of C, and is considered harmful by some; I personally believe that macros are a powerful feature of the language, and can be beneficial when they're not abused.)

The solution for function-like macros proposed by tftv256 is so brilliant that nobody else seems to have thought of it before.

I used to define this sort of macros like #define FOO() foo(), bar()

This also works fine, even with a piece of logic: #define FOO(x) (x) ? foo1() : foo2(), bar()

But what if you need a for statement in your definition? And what do you do if you have use another persons definition and this is one of the sort: #define FOO() { foo(); bar(); }

The most unpleasant example I ever found was #define SURPRISE(x) if ((x)) foo()

You will really get surprising results if you use this example as in: if (a) SURPRISE(b); else somethingelse();

You expect somethingelse() to be executed if a is 0, but is isn't!

To avoid problems with using functions which might be implemented as function-like macros, I always use blocks and never statements where both are allowed by the incredible C syntax. So:

if( bort ) { FOO(); } else { bam = bob; } and if ( a ) { SURPRISE(b); } else { somethingelse(); }

The braces may be considered ugly, but they make sure that the program does what I expect it to do.

Actually, this can be used in another case, to test for errors:

do {
    if(!test1()) break;
    if(!test2()) break;
    if(!test3()) break;
    /* actual code */
} while(0);

This is pretty useless in C, since this sort of thing is much better handled by goto (yes, yes, I know, but even the Linux kernel does it). And higher level languages can use exceptions. But in PHP, before version 5, this was the best way to do error testing and defensive programming.

Log in or register to write something here or to contact authors.