Mechanics of macros

Naming

I use names identical to function names for expression macros (macros that return values). In general, I use all upper case names for block macros (macros that have multiple statements). The intent is that, for efficiency, we will freely interchange expression macros and functions, so there should be no distinction between the two. However, block macros may need special treatment, and the user, by looking at the all upper case name, will conclude that something special is going on.

do while(0)

Block macros should be enclosed by a do { ... } while(0) construct. The reason is simple - we want the user of the macro to be forced to put a ; after the use of the macro. Specifically, if we defined the SWAP macro as:


	#define SWAP(_x, _y) \
	  { \
	    int	_t = (_x); \
	    (_x) = (_y); \
	    (_y) = _t; \
	  }

In this case both SWAP(s, t) and SWAP(s,t); will be accepted by the compiler. However, if we enclosed the definition with a do {...} while(0), only the second case would compile.

Equivalences

Here are some equivalences between standard C constructs and their macro equivalents


	v = expr;		(void)((v) = expr)

	st1;			(st1), (st2)
	st2;

	if( pred ) {		(pred)?(st1):(st2)
	  st1;
	}
	else {
	  st2;
	}

	return (expr);		(expr)

Dealing with Local Variables

In an expression macro, local variables are best handled by having the macro take an extra parameter that is used as a scratch value.


	#define	swap(_x, _y, _t) \
	  ( (_t) = (_x), \
	    (_x) = (_y), \
	    (_y) = (_t) )

In a block structured macro, of course, one can declare a variable with local scope. Try and pick a name that will not be confused with one of the parameters. By convention, I prefix all local scope variables defined in a block macro with an _. Thus


	#define SWAP(_x, _y) \
	  do { \
	    int	_t = (_x); \
	    (_x) = (_y); \
	    (_y) = _t; \
	  } while(0)

Assume that we local scope variables t instead of _t. In that case, if the macro was invoked as SWAP(s, t), it would incorrectly expand to:


	do {
	  int t = s;
	  s = t;
	  t = s;
	} while(0)

Example

Consider the following example:


	Foo
	head_foo_list(
		FooList *	p_list
		)
	{
	  if( *p_list ) {
	    return value_foo_list(*p_list);
	  }
	  else {
	    return 0;
	  }
	}

Using the rules above, we can construct an expression macro as:


	#define head_foo_list(_p_list) \
	  ( (*p_list)?\
	      value_foo_list(*p_list):\
	      (0))


Next Prev Main Top Feedback