[comp.std.c] Summary of variable args in macros

bradb@ai.utoronto.ca (05/03/89)

I recieved a number of replies about my query regarding variable
numbers of parameters in macros.  As I suspected, everyone told
me that I can't do it, and that's OK, but I did get some interesting
workarounds.  The two approaches were to trick the macro expander
into thinking it only has one argument that is made up of some
macros that themselves expand into commas.  Ick, but it works.
The other approach is to pass an entire statement.  I'd thought
of that one, and it's a lot more general, but it too seems to
be an ugly hack.

Just in case anyone is interested, I gave up on variable-argument
macros and wrote trace(), which prints a message, and traceVal(),
which prints the value of a variable.  Oh well.

---------------------------------------------------------------------

Geoff Clare <gwc@root.co.uk> writes:

Most replies you get will probably suggest using double parentheses
like this:

	#define trace(s)  (void) fprintf s
	trace( (stderr, "Entering zot(), arg is %d", arg) );

However, I prefer to use the following trick:

	#define _ ,
	#define trace(s)  (void) fprintf( stderr, s )

	trace( "Entering zot(), arg is %d" _ arg );
					  ^ note: this space must be there

----------------------------------------------------------------------


David Keppel <pardo@june.cs.washington.edu> suggests passing the
entire argument list to printf as a parameter:

If you're really in to sadism (but bewarned: I warned you!)

    #define	BLETCH(x)	printf x
	...
	BLETCH (("arg %d\n", arg));
	...
	BLETCH (("no arg\n"));

You'll find life *much* easier if you can do something like STMT.
I think that you probably can, even in this bizzare case.

    #define STMT(s)	do { s } while(0);
    #define BLETCH(x)	STMT(x)
	...
	BLETCH (("arg %d\n", arg););
	...
	BLETCH (("no arg\n"););

----------------------------------------------------------------------------

Mark Brader <msb@sq.sq.com> says pretty much the same thing as Geoff:

Right, you can't do it.  The standard workaround is:

	#define trace(s)  fprintf s
	trace((stderr, "Entering zot(), arg is %d\n", arg));

Notice the double parentheses; notice that the stderr has to be in the call.
People who use this tend to use it with printf() rather than fprintf(), for
just that reason.

As a matter of readability, it's better to make macros expand to expressions
rather than statements wherever possible -- because they look like function
calls and function calls are expressions -- so your first version would have
been better written with the "{" and "; }" omitted, as I have done in mine.

-------------------------------------------------------------------------

Thanks again to all.

					(-:  Brad Brown  :-)
					bradb@ai.toronto.edu