[comp.lang.c] SUMMARY #define DEBUG

gordon@hermod.cs.cornell.edu (Jeffrey Adam Gordon) (05/04/90)

Thanks to all who have replied and posted.  I'm getting a lot of
repeated suggestions at this point so here's a summary (the first is
the one I have chosen to use.  I prefer it because it does not leave
any dead code (except a semicolon) lying around and does not rely on a
smart compiler optimizing things away.
-----------------------------------------------------------------------
The most common thing I've seen goes something like:

#ifdef DEBUG
#define DPRINT(x) printf x
#else
#define DPRINT(x)
#endif

then in your code do:

    DPRINT(("stuff %d\n", abc));

note that the double paren's are crucial, it makes 1 arg for the
preprocessor, which either comes after printf or is discarded.
----------------------------------------------------------------------
another way would be to use something like this:

#define DEBUG 0
...
if (DEBUG) printf(....);
...

if your compiler is worth anything, it should optimize out the printf if
DEBUG is 0.  if you set DEBUG to 1 at the compile line, then the printf's
will be in place, and the compiler should still optimize out the "if" since
it is always true.
-----------------------------------------------------------------------
#ifdef DODEBUG
#   define DEBUG printf
#else
#   define DEBUG (void)
#endif DODEBUG

Now when you say

    DEBUG(format, var1, var2, var3);

it expands to one of

    printf(format, var1, var2, var3);

or

    (void)(format, var1, var2, var3);

Both of which are legal statements; the first is a function call, the
second is a parenthesized comma-expression.  Any reasonable compiler will
detect that the second form can be completely optimized out, since the
value is never used (in fact, it's explicitly thrown away).

One effect of this, which may be considered either a drawback or an
advantage depending on your point of view, is that if you accidentally
use an operation that has side effects in a DEBUG statement, that
operation will be executed regardless of the definintion of DODEBUG; the
compiler is obligated not to eliminate side-effected sub-expressions from
the comma-expression.  On the other hand, side effects should still be
avoided, because the *order* of evaluation may differ for function param
lists and comma-exprs.
-----------------------------------------------------------------------
>
	#define DEBUG1(x)	printf(x)
	#define DEBUG2(x,y)	printf(x,y)
	#define DEBUG3(x,y,z)	printf(x,y,z)

etc.  That's the best I've seen so far.  It's ugly, and requires knowing lots
of names, but it works.
-----------------------------------------------------------------------

Some solutions also had a debug level but this was more than I needed.

Thanks all.

- Jeff

yedinak@motcid.UUCP (Mark A. Yedinak) (05/07/90)

gordon@hermod.cs.cornell.edu (Jeffrey  Adam Gordon) writes:

: Thanks to all who have replied and posted.  I'm getting a lot of
: repeated suggestions at this point so here's a summary (the first is
: the one I have chosen to use.  I prefer it because it does not leave
: any dead code (except a semicolon) lying around and does not rely on a
: smart compiler optimizing things away.

: Some solutions also had a debug level but this was more than I needed.

I have been following the thread concerning the debug mechanisms, and have
decided to include my variation. It is primarily used on UNIX systems, and uses
environment variables to define the level of debugs statements which will be
selected. Again, all the debug statements can be compiled out of the code simply
by undefining the #define PROG_DEBUG. 

Following is the macro definition and an sample program.

|--------------------------- Cut Here -----------------------------------------|

#include <stdio.h>

#define PROG_MAIN	/* Defined in the file containing main () */

/*******************************************************************************
*
*  Macro:	PROG_DEBUG
*  Purpose:	The following definition is used to define a in line
*		debug mechanism which can be compiled out of the code.
*		In addition, when compiled in, it can be switched off
*		using an environment variable. If the environment
*		variable is set, the debug code is executed. The macro
*		will also allow settable modes of debug statements. The
*		value of the environment variable will be 'AND' with
*		the coded debug level, if the level was selected, the
*		statements will be executed. A debug macro can be forced
*		to be displayed simply by setting the code level to 255.
*		Likewise, if the envrionment variable is set to 255, all
*		debug statements will be executed.
*
*		Range of ENV_DEBUG is 0 <= ENV_DEBUG <= 255
*
*		This allows the in line debug code to be accessed easily.
*  Arguments:	L	The coded debug level.
*		S	The c statements desired in the debug code. These
*			can be any valid c constructs. I am not sure if
*			there is a maximium length for the lines, however
*			I have been able to place a significant amount of
*			code in a single debug macro.
*  Return:	None
*  Author:	Mark A. Yedinak
*
*******************************************************************************/

#ifdef PROG_DEBUG
#	define 	init_debug	debug_flag = (char)  (atoi \
				(getenv ("ENV_DEBUG")==NULL\
				?"":getenv ("ENV_DEBUG")))
#
#	define	debug(L,S)	if (debug_flag & (L)) { S }
#	ifdef	PROG_MAIN
	    extern	char	*getenv ();
	    char		debug_flag;
	    FILE		*dbg_fp;
#	else
	    extern	char	debug_flag;
	    extern	FILE	*dbg_fp;
#	endif
#else
#	define	init_debug	/**/
#	define	debug(L,S)	/**/
#endif


main ()
{
    init_debug;

    debug (1,
	dbg_fp = stdout;
	printf ("Executing Level 1 debug code\n");
	fflush (dbg_fp);
    );

    debug (2,
	dbg_fp = stdout;
	printf ("Executing Level 2 debug code\n");
	fflush (dbg_fp);
    );

    debug (255,
	dbg_fp = stdout;
	printf ("Forced Execution of debug code\n");
	fflush (dbg_fp);
    );

    printf ("Executing in-line code\n");
}

|--------------------------- Cut Here -----------------------------------------|
-- 
Mark A. Yedinak - uunet!motcid!yedinak 		*  "Don't take life too
Motorola - General Systems Sector		*   seriously, you will
3205 Wilke Road, Arlington Heights, IL 60004	*   never get out of it
708-632-2874  (Usual Disclaimers)		*         ALIVE!"