[comp.lang.c] Using macros as statements

smking@lion.waterloo.edu (Scott M. King) (01/16/90)

In article <721@eedsp.eedsp.gatech.edu> baud@eedsp.UUCP (Kurt Baudendistel) writes:
:Be careful, however, of the nasty C preprocessor, which will make this
:nice looking and appealing definition:
:  #define SWAP(a,b) {typeof (a) tmp; tmp=a; a=b; b=tmp}
:fail in many cases, like
:  if (x < y)
:    SWAP (x, y);	// bracketing of SWAP makes the `;' extraneous
:  else			// and fatal
:    x = y;
:
:Kurt Baudendistel --- GRA
:Georgia Tech, School of Electrical Engineering, Atlanta, GA  30332
:internet: baud@eedsp.gatech.edu         uucp: gatech!gt-eedsp!baud

To make a macro behave exactly as a statement, replace the { and } in
the macro definition with START_MACRO and END_MACRO:
#define START_MACRO		do {
#define END_MACRO		} while ( 0 )

The compiler should catch uses with too few or too many semi-colons here.

(Note that another version I have seen has very unexpected effects if the
semi-colon is left off the macro usage:
#define START_MACRO		if ( 1 ) {
#define END_MACRO		} else
)
Scott M. King, Software Devlopment Group, University of Waterloo

david@sun.com (``Bob'' is the gun and YOU are the bullet...) (01/17/90)

In article <19840@watdragon.waterloo.edu> smking@lion.waterloo.edu (Scott
M. King) writes:
>To make a macro behave exactly as a statement, replace the { and } in
>the macro definition with START_MACRO and END_MACRO:
>#define START_MACRO		do {
>#define END_MACRO		} while ( 0 )

Unfortunately this is not lint-compatible ("constant in conditional
context").  I use a slight variation:

#ifdef lint
int _ZERO_;
#else
#define	_ZERO_ 0
#endif

#define	_STMT(s)	do { s } while (_ZERO_)

#define	FOO(bar)	_STMT(if (bar) frob();)

-- 
David DiGiacomo, Sun Microsystems, Mt. View, CA  sun!david david@eng.sun.com

steveh@emtek.UUCP (Steve Hollasch) (01/21/90)

> To make a macro behave exactly as a statement, replace the { and } in
> the macro definition with START_MACRO and END_MACRO:
> #define START_MACRO  do {
> #define END_MACRO    } while ( 0 )
> 
> The compiler should catch uses with too few or too many semi-colons here.
> 
> (Note that another version I have seen has very unexpected effects if the
> semi-colon is left off the macro usage:
> #define START_MACRO  if ( 1 ) {
> #define END_MACRO    } else

    I use two basic forms for multi-statement macro definitions, and
ALWAYS terminate a macro invocation with a semi-colon (I think of
macro invocations as inline functions, so this makes sense).

    An alternative method is the following:

#define MACRO(a,b,c) \
(   (a)[0] = (b)[0] + (c)[0],  \
    (a)[1] = (b)[1] + (c)[1],  \
    (a)[2] = (b)[2] + (c)[2]   \
)

    That is, define the macro as a throwaway expression.  This method
seems 'cleaner' to me, since there are no implied tests.  The
trailing-else (or single-loop) method, however, is superior in that
it allows any kind of code within the macro body.  NOTE:  This
includes variable declarations (as in swap routines)!

_______________________________________________________________________________
Steve Hollasch [uunet!emtek!steveh]                              Tempe, Arizona