[net.lang.c] Disappearing function call

drw@cullvax.UUCP (Dale Worley) (10/01/86)

What I want to do is to write a function call of a variable number of
arguments:

	debug(x, y, z, ...)

that will generate no code when the symbol DEBUG is not defined, but
generate a call of some function (say, debug_()) when it is.  If
debug() always had the same number of arguments, we could use

	#ifdef DEBUG
	#define debug(x, y, z)	debug_(x, y, z)
	#else
	#define debug(x, y, z)	/* null */

but macros aren't allowed to have a variable number of arguments.

The best solutions I've heard so far are:

1) We write

	debug(x Z y Z z)

using "Z" instead of ",".  Using the definitions

	#ifdef DEBUG
	#define debug(x)	debug_(x)
	#define Z		,
	#else
	#define debug(x)	/* null */
	#endif

works, since the "Z"s are turned into "," after the call of debug() is
expanded.  This is ugly because you have to write "Z" instead of ",".

2) We write

	debug(x, y, z))

Using the definitions

	#ifdef DEBUG
	#define debug		(debug_
	#else
	#define	debug		debug1(
	#define	debug1(x)	/* null */

This works when DEBUG is off by replacing the call to debug() to a
call to debug1() with one argument, which is then ignored.  This ugly
because of the mismatched parentheses.

Is there a good way to do this?

Dale

few@well.UUCP (Frank Whaley) (10/02/86)

In article <357@cullvax.UUCP> drw@cullvax.UUCP (Dale Worley) writes:
>What I want to do is to write a function call of a variable number of
>arguments:
>	debug(x, y, z, ...)
>that will generate no code when the symbol DEBUG is not defined, but
>generate a call of some function (say, debug_()) when it is.

Numerous ugly examples deleted.

I had to do this just recently, and took advantage of the fact that my
compilers "optimize out" code like this:

	if (0) function();

So assuming:

	#ifdef	DEBUG
	#define	_DEBUG	1
	extern void _debug(char *,)	/*  debugging printf()  */
	#else
	#define	_DEBUG	0
	#endif
	#define	debug	if(_DEBUG)_debug

a statment like:

	debug("%d:%d:%d\n", a, b, c);

becomes either:

	if(1)_debug("%d:%d:%d\n", a, b, c);
or
	if(0)_debug("%d:%d:%d\n", a, b, c);	/*  no code generated  */

All of my compilers generate the strings anyway, so I used a set of external
strings (bracketed by #ifdef's) for all debugging messages.  Some compilers
require an optimizer pass to eat the dead code.

-- 
Frank Whaley
Senior Engineer, Beyond Words
UUCP:		hplabs!
	   ihnp4!ptsfa!
	seismo!lll-crg!well!few
ARPA:	well!few@lll-crg.ARPA

Water separates the people of the world;
wine unites them.

marcus@ihlpl.UUCP (Hall) (10/02/86)

In article <357@cullvax.UUCP> drw@cullvax.UUCP (Dale Worley) writes:
>What I want to do is to write a function call of a variable number of
>arguments:
>
>	debug(x, y, z, ...)
>
>that will generate no code when the symbol DEBUG is not defined, but
>generate a call of some function (say, debug_()) when it is.  If
>debug() always had the same number of arguments, we could use
>
>	#ifdef DEBUG
>	#define debug(x, y, z)	debug_(x, y, z)
>	#else
>	#define debug(x, y, z)	/* null */
>
>but macros aren't allowed to have a variable number of arguments.

How about this:

#ifndef	DEBUG
#define debug
#endif

and writing in the code:

	debug(a,b,c)


If DEBUG is turned on, nothing will happen to the debug statements, so a
call to debug will be produced (as you would expect).  If DEBUG isn't
defined, the symbol "debug" will be pre-processed out of existance, so
the compiler will see an expression like:

	(a,b,c)

If the arguments don't produce any side effects, I believe that most decent
compilers will not emit any code (or at least the optimizer should be able
to detect a load of a useless register.  If the debug function returns a
value that is checked, when DEBUG is turned off, the value will be the last
parameter, which will generate code, but I don't suppose that the debug
routine actually returns a value.  Simple expressions as arguments to the
debug function should also produce no code if DEBUG is turned off, but it
is possible that complex expressions could fool the compiler into generating
code for parts of the expression then throwing the result away.  One way
that this could generate code is if the optimizer has to remove the useless
loads and this is the last expression in the function (so that there isn't
a return statement).  If a value is loaded into the register that is used
for the return value, the optimizer may think that that is the return value
and thus it wouldn't think it was a useless load.

If any of the arguments have side effects or involve function calls (with
potential side effects there!), these will (and should) always be generated.
However, I don't think that it is likely that you would want to be doing
this sort of thing in a call to a debugging macro.

Are there any problems with doing this?  I suppose that some pre-processors
could choke on the parenthesis after debug in the invocation, since debug
is #defined as a parameter-less macro, but my pre-processor (SVR2) doesn't.

Marcus Hall
..!ihnp4!ihlpl!marcus

geoff@ism780c.UUCP (Geoff Kimbrough) (10/02/86)

In article <357@cullvax.UUCP> drw@cullvax.UUCP (Dale Worley) writes:
>What I want to do is to write a function call of a variable number of
>arguments:
>	debug(x, y, z, ...)
     I've used this construction
#if DEBUG
#define debug(X)  printf X      /* note NO parentheses */
#else
#define debug(X)
#endif
  and written
debug(( "stuff =%x blek = %d", var1,var2))    /* note double parentheses */
  seems to work for me.
  You're welcome.

kenny@uiucdcsb.cs.uiuc.edu (10/03/86)

/* Written 12:44 pm  Oct  2, 1986 by marcus@ihlpl.UUCP in uiucdcsb:net.lang.c */
>In article <357@cullvax.UUCP> drw@cullvax.UUCP (Dale Worley) writes:
>>What I want to do is to write a function call of a variable number of
>>arguments:
>>
>>	debug(x, y, z, ...)
>>
>>that will generate no code when the symbol DEBUG is not defined,
[...]
>How about this:
>
>#ifndef	DEBUG
>#define debug
>#endif
>
>and writing in the code:
>
>	debug(a,b,c)
>
>If DEBUG is turned on, nothing will happen to the debug statements, so a
>call to debug will be produced (as you would expect).  If DEBUG isn't
>defined, the symbol "debug" will be pre-processed out of existance, so
>the compiler will see an expression like:
>
>	(a,b,c)
[...]
>Are there any problems with doing this?  I suppose that some pre-processors
>could choke on the parenthesis after debug in the invocation, since debug
>is #defined as a parameter-less macro, but my pre-processor (SVR2) doesn't.
>
>Marcus Hall
/* End of text from uiucdcsb:net.lang.c */

If you invoke it in the code as

	debug (a, b, c)
	     ^ Note the space!

then no preprocessor should ever confuse it; macros with parameters are
recognized only if no space intervenes between the macro name and the
left parenthesis.

Kevin Kenny			     UUCP: {ihnp4,pur-ee,convex}!uiucdcs!kenny
University of Illinois at Urbana-Champaign	       CSNET: kenny@UIUC.CSNET
``Don't worry; I'm a New Yorker!'' ARPA: kenny@B.CS.UIUC.EDU (kenny@UIUC.ARPA)

plocher@puff.wisc.edu (John Plocher) (10/03/86)

<f u cn rd ths, u hv no ln etr>

There were some debug routines posted in net.sources which use this format:

#ifdef DEBUG
#  define TRACE printf
#else
#  define TRACE
#endif
 ...
    TRACE("The error '%s' is on line %d\n", errorname, lineno);
 ...
which expands into
    printf(...) if DEBUG is defined,
and into
    (...) if not.   Note that (...) does NOT GENERATE CODE, but is rather
		    just an expression.

-- 
		harvard-\         /- uwmacc!uwhsms!plocher        (work)
John Plocher     seismo-->!uwvax!<
		  topaz-/         \- puff!plocher                 (school)

civil flames (ie. ones which are WORTH reading) only, please!
"Never trust an idea you get sitting down" - Nietzche

franka@mmintl.UUCP (Frank Adams) (10/06/86)

In article <357@cullvax.UUCP> drw@cullvax.UUCP writes:
>What I want to do is to write a function call of a variable number of
>arguments:
>
>	debug(x, y, z, ...)
>
>that will generate no code when the symbol DEBUG is not defined, but
>generate a call of some function (say, debug_()) when it is.

Here's a possibility which is slightly ugly, as all the others are, but the
ugliness is in a different place.  Write:

#ifdef DEBUG
#define debug(a) debug_ a
#else
#define debug(a)
#endif

Now, write your debug statements with an extra pair of parentheses:

   debug((x, y, z, ...));

I'm not necessarily recommending this; it's just an idea.

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Multimate International    52 Oakland Ave North    E. Hartford, CT 06108

drw@cullvax.UUCP (Dale Worley) (10/06/86)

I have received an elegant (and in retrospect, obvious) solution to
this problem from someone whose name I can't remember:

	#ifdef DEBUG
		#define    debug(x)	debug_ x
	#else
		#define    debug(x)	/* null */
	#endif

You then write function calls:

	debug((a, b, c))

Dale

greg@utcsri.UUCP (Gregory Smith) (10/06/86)

In article <357@cullvax.UUCP> drw@cullvax.UUCP (Dale Worley) writes:
>What I want to do is to write a function call of a variable number of
>arguments:
>
>	debug(x, y, z, ...)
>
>that will generate no code when the symbol DEBUG is not defined, but
>generate a call of some function (say, debug_()) when it is.  If

You could write

	debug( ( x,y,z ) );

In the code, and

#ifdef	DEBUG
# define debug(list) _debug list
#else
# define debug(list)
#endif
-- 
----------------------------------------------------------------------
Greg Smith     University of Toronto      UUCP: ..utzoo!utcsri!greg

faustus@ucbcad.BERKELEY.EDU (Wayne A. Christopher) (10/07/86)

I just thought of this one:

#ifdef DEBUG
	#define    debug	debug_function
#else
	#define    debug	sizeof
#endif

	Wayne

john@frog.UUCP (John Woods, Software) (10/07/86)

> What I want to do is to write a function call of a variable number of
> arguments:
> 	debug(x, y, z, ...)
> that will generate no code when the symbol DEBUG is not defined, but
> generate a call of some function (say, debug_()) when it is.

Try:

#ifdef DEBUG
#define debug(x) x
#else
#define debug(x)
#endif

	debug( puts("Shut 'er down, Scotty, she's sucking mud again."); )

The extra layer of indirection may feel irritating, but it also allows

	debug( if (op == NULL) exit(puts("RATS RATS RATS [#566, para. 1]")); )

It's quick, it's easy, it works.

--
John Woods, Charles River Data Systems, Framingham MA, (617) 626-1101
...!decvax!frog!john, ...!mit-eddie!jfw, jfw%mit-ccc@MIT-XX.ARPA

"Don't give me this intelligent life crap,
just find me a planet I can blow up."

chris@umcp-cs.UUCP (Chris Torek) (10/08/86)

The problem: to include debug calls, with variable argument lists,
such that they may be conditionally compiled (a la #if), but without
cluttering the source with `#ifdef'.

Two standard solutions, and their problems:

1:	#ifdef DEBUG
	#define	debug(x)	debug_ x
	#else
	#define	debug(x)	/* null */
	#endif
	...
	foo(foostring, foovalue)
		char *foostring;
		int foovalue;
	{
		debug(("foo(%s, %d)", foostring, foovalue));
		...

Problem: The call to `debug' `looks funny'.  (This is not all that
trivial; style is important to readability.)

2:	#ifdef DEBUG
	#define	debug
	#else
	#define debug debug_
	#endif
	...
		debug("foo(%s, %d)", foostring, foovalue);
		...

Problems: Some preprocessors apparently gripe about argument
mismatches, requiring an extra space: `debug ("foo(%s, %d)", ...)'.
Other compilers generate code and/or data even when DEBUG is turned
off, since this preprocesses to

		("foo(%s, %d)", foostring, foovalue);

A third solution, which no one seems to have proposed here, is to
write your own `pre-prepocessor processor'.  Here for your amusment
and/or edification is a lex specification that matches C code
inputs.  I used it for `grim', a program pessimiser.  (An optimiser
makes code better, so a pessimiser makes code worse.  It was fun to
write.)

Caveat: the lexer matches comments in their entirety, and thus
requires a large lex buffer.  This can be avoided by using `BEGIN'
and extra lex states, but I wanted the comment text too.  It also
does not match C perfectly, only as well as I needed.  It should,
however, suffice for a debug remover.

%{
#undef YYLMAX
#define YYLMAX		32768
#define	yywrap()	1
%}
id				[a-zA-Z_][a-zA-Z0-9_]*
whitespace			[ \t\n]
comment				\/\*(\*[^/]|[^*])*\*+\/
charconst			\'(\\\'|[^'])*\'
strings				\"(\\\"|[^"])*\"
number				[0-9]+
%%
^#[ \t]*define[ \t]+.*	{ MungeNumberDefine(); }
^#.*			{ printf("%s", yytext); }
{comment}		{ MungeComment(); }
{strings}		{ printf("%s", yytext); }
{charconst}		{ printf("%s", yytext); }
{id}			{ MungeID();}
{whitespace}		{ putchar(yytext[0]); }
{number}[lL]		{ printf("%s", yytext); }
{number}		{ printf("%s", yytext); }
.			{ putchar(yytext[0]); }
%%
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu

franka@mmintl.UUCP (Frank Adams) (10/08/86)

In article <3731@umcp-cs.UUCP> chris@umcp-cs.UUCP writes:
>The problem: to include debug calls, with variable argument lists,
>such that they may be conditionally compiled (a la #if), but without
>cluttering the source with `#ifdef'.
>
>2:	#ifdef DEBUG
>	#define	debug
>	#else
>	#define debug debug_
>	#endif
>	...
>		debug("foo(%s, %d)", foostring, foovalue);
>		...
	(the #defines here should be reversed)
>Problems: [...]
>Other compilers generate code and/or data even when DEBUG is turned
>off, since this preprocesses to
>
>		("foo(%s, %d)", foostring, foovalue);

This problem is not totally dependent on the quality of the compiler.  If
any of the arguments to the debug_ function involves a function call, the
compiler *must* generate code for it.  E.g.,

	debug("x=%d, sin(x)=%d", x, sin(x));

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Multimate International    52 Oakland Ave North    E. Hartford, CT 06108

guido@mcvax.uucp (Guido van Rossum) (10/11/86)

In article <357@cullvax.UUCP> drw@cullvax.UUCP (Dale Worley) writes:
>What I want to do is to write a function call of a variable number of
>arguments:
>
>	debug(x, y, z, ...)
>
>that will generate no code when the symbol DEBUG is not defined, but
>generate a call of some function (say, debug_()) when it is.  If
>Is there a good way to do this?

If you are willing to write extra parentheses but want them to match,
write this:

	#ifdef DEBUG
	#define debug(x) debug_ x
	#else
	#define debug(x) /* empty */
	#endif

and call as follows:

	debug((x, y, z, ...));

-- 
	Guido van Rossum, CWI, Amsterdam <guido@mcvax.uucp>

mcg@omepd.UUCP (10/13/86)

You guys are all thinking too hard.  Even the venerable Chris Torek has
proposed a solution more complex than needed.  On any compiler likely to
be used for production code, the optimizer will generate no code
whatsoever for the following fragment:

	#define DEBUG	0	/* set to 1 to turn debugging on */

	...

	if (DEBUG) debug(...);

Similarly, in the case of '#define DEBUG 1', the unneccesary test will
be elided.
 
In the idiom of the original posting, the example is:

	#define	debug	if(DEBUG) debug

	debug(x,y,z);

Though care must be taken in using this form in un-braced if statements
that have else clauses.

The preprocessor solutions have the intoxicating air of complexity about
them, but, in my experience, this solution proves easiest and most
effective.  Why look for trouble?  Trouble will find you.

S. McGeady

mcvoy@rsch.WISC.EDU (Lawrence W. McVoy) (10/27/86)

In article <162@omepd> mcg@omepd.UUCP (Steven McGeady) writes:
>
>You guys are all thinking too hard.  
>
>	#define DEBUG	0	/* set to 1 to turn debugging on */
>	...
>	if (DEBUG) debug(...);
>
>Similarly, in the case of '#define DEBUG 1', the unneccesary test will
>be elided.
> 
>In the idiom of the original posting, the example is:
>
>	#define	debug	if(DEBUG) debug
>
>	debug(x,y,z);

I came into this late, so you might already know this, but try this on for 
size anyway:

# ifdef		DEBUG
#   define	debug(x)	fprintf x
# else
#   define	debug(x)
# endif

.....

	debug((stderr, "Control string", arg1, arg2, ... argn));

Cute, isn't it?  I stole it out of the src to enscript (adobe something or
other).
-- 
Larry McVoy 	        mcvoy@rsch.wisc.edu, 
      		        {seismo, topaz, harvard, ihnp4, etc}!uwvax!mcvoy

"They're coming soon!  Quad-stated guru-gates!"

andy@Shasta.UUCP (10/28/86)

#define	DEBUG	1 /* or 0 as appropriate */

#define	debug	if( DEBUG ) fprintf

(Replace fprintf with the appropriate function.)

Then you can write:
    debug( stderr, "wrong args %d, %s, %p\n", d, s, p ); /* %p is bogus */

Either your compiler eliminates dead code or it doesn't.
If it doesn't, other dead code and missed opportunities to generate
good code will swamp the overhead of checking if 0 is still 0 and
skipping the fprintf.  If it does, the fprintf (and its args) will be
removed.

-andy

ps - Yes, I know my debug will pick up a following "else".  I use "extra"
{}'s and debug( <args> ) shouldn't be followed by an "else" anyway; I'll
document that feature and let it slide.  It is difficult to handle all
possible constraints with something as limited as cpp; "debug( (<args>) )"
grates on me.

I'd rather write "if( DEBUG ) <code>" directly than "debug( <args> )"
because it doesn't restrict <code>.
-- 
Andy Freeman
UUCP:  ...!decwrl!shasta!andy forwards to
ARPA:  andy@sushi.stanford.edu
(415) 329-1718/723-3088 home/cubicle