[Swan-dev] safe C macros

D. Hugh Redelmeier hugh at mimosa.com
Thu Dec 11 09:36:49 EET 2014


C preprocessor macros replace a macro invocation with a sequence of 
tokens.  This substitution can and does cross syntactic boundaries and 
this makes reading code difficult and error-prone.

Rules (exceptions and fine points spelled out later):

1. all macro bodies should be wrapped in () or {} to prevent
   surprising results

	#define pow2()  (1 << n)
	think about: pow2(5) * 3

	#define warn(m)  { horrors++; printf("warning: %s\n", m); }
	think about: if (bad) warn("yikes");

2. all macro parameter references within macro bodies should be
wrapped in () to prevent surprising results.

	#define squarea(n)  ((n) * (n))
	think about: squarea(3+2)

These rules have been violated in a number of cases in libreswan.

I've tried to fix this in commit
66f8e13d4ff538e2227243c93f6196633f2f7f4e.  Actually, that was an
accidental commit -- I meant to fix another problem but committed them
together.  So the commit message only describes the other problem.


=== Exceptions and fine points ===

== exception 0: when you are doing something intentionally tricky ==

If you really want a macro to not be a complete syntactic unit, adding
{} or () will foil you.

	#define forever for(;;)
			
	#define log(x) { printf("logging" x); }

We have some of this.  It must be done VERY judiciously.


== {} vs do {} while (0) ==

Technically { } isn't quite right.  Consider the case

	if (bad)
		warn(m);
	else
		goodness++;
The problem is that the ; before the else is not needed and is parsed
as an empty statement, preventing the else from being connected with
the if.  This will cause a compile-time error message. A fix is
to add braces:

	if (bad) {
		warn(m);
	} else {
		goodness++;
	}

(I added the second set of braces for symmetry.)

Instead, you can use this contorted and obscure structure in the
definition:

	#define warn(m) do { horrors++; printf("warning: %s\n", m); } while (0)

This convention is so ugly I don't use it.  The number of extra cases 
handled is miniscule (I've found none in our code base).  And the failure 
of the simple braces is always diagnosed by the compiler and easy to fix.


== when () around a macro body isn't needed ==

If the macro body is so simple that it cannot be re-interpreted by
embedding, then the () isn't needed.  The prime example in our code
base is a macro body is a numeral:

	#define red	3


== when () around a macro argument isn't needed ==

	when the macro argument appears in a place that cannot
	re-interpret any argument.  Most commonly, when the argument
	appears by itself as an argument:

	#define bytes(x)	sizeof(x)


== when {} around a macro body isn't needed ==

If the macro body is a single statement.  Even then braces are a
little safer:

	#define ding(x) printf("\a%d\n", s)

	ding(4) + 3;	/* undiagnosed mistake */


More information about the Swan-dev mailing list