[comp.lang.c] preprocessor directives in macros

geoff@rdahp.UUCP (Geoff Walsh) (12/02/88)

Being a new user on the net, I'm not sure whether this has been
discussed before.  If so, please let me know.

I'm trying to conditionally include diagnostic messages in my code
that I can turn on or off at compile time.  Also, I'd like to be able
to set the level and type of message.  I can't quite get the compiler
to do what I want, so I assume its not portable to a compiler that
does it.

One way that does work is:

#define TESTA   0
#define TESTB   6
#define TESTC   3
... etc.
#define diagprintf(TestCriteria,TestLevel,Fmt) \
    if (TestCriteria >= TestLevel) printf Fmt

then do:

    some code
    diagprintf (TESTB, 8, ("B condition is %d\n", bcond));
    some more code

This works and most compiler optimizers are smart enough to recognize
dead code [if (TESTB (==6) >= 8)] and throw away the code for the rest
of the expression.  (The if test value can be determined at compile time.)

However, the compiler will usually leave the unreferenced string:
    "B condition is %d\n"
in the string pool.  This isn't a problem for debugging, but for the
final release of the code, I don't want all these messages in the final
executable, even though the dead code is removed (i.e. by setting all
TEST? above to zero).

I tried to use the preprocessor with something like:

#define diagprintf(TestCriteria,TestLevel,Fmt) \
    #if (TestCriteria >= TestLevel)\
        printf s\
    #endif

to get the preprocessor to eliminate dead code AND the strings associated
with Fmt, but the compiler didn't like this.  I get an error message
like "Expected formal macro parameter" with one compiler, and " # operator
should be followed by a macro argument name" with another, and the compiles
fail.  An examination of the preprocessed output shows that the preprocessor
gets a bit mixed up.  Other C compilers tested with each produce different,
but still not the desired, results.  (Both MS-D*S and U*IX C compilers were
used.  The compilers were Microsoft C 5.1, HP-UX 6.2 cc, gcc, and HP
cc68020 cross compiler.)  The questions are:

    1.  Is there any portable, standard way to do something like this with
        the preprocessor?
    
    2.  Is this legit in ANSI C and do I need to just wait for the
        next version of my compiler?  If not, is there an ANSI C way?
--
Geoff Walsh, R & D Associates, Marina del Rey, CA
rdahp!geoff, rdahp!geoff@sm.unisys.com

garnett@a.cs.okstate.edu (John Garnett) (12/05/88)

From article <122@rdahp.UUCP>, by geoff@rdahp.UUCP (Geoff Walsh):
> 
> I tried to use the preprocessor with something like:
> 
> #define diagprintf(TestCriteria,TestLevel,Fmt) \
>     #if (TestCriteria >= TestLevel)\
>         printf s\
>     #endif
> 
> to get the preprocessor to eliminate dead code AND the strings associated
> with Fmt, but the compiler didn't like this.  I get an error message
> like "Expected formal macro parameter" with one compiler, and " # operator

How about using something like the following:

#ifdef DEBUG
#define diagprintf(TestCriteria,TestLevel,Fmt) \
	if (TestCriteria >= TestLevel) {printf Fmt; fflush(stdout); }
#else
#define diagprintf(TestCriteria,TestLevel,Fmt)
#endif

Then you can control whether or not the debug code is even compiled
by using 'cc -DDEBUG code.c' to include debug code or 'cc code.c'
to prevent the code from being sent to the compiler.

John Garnett


~ John Garnett                         Internet: garnett@a.cs.okstate.edu
~ Computing and Information Sciences   UUCP: {cbosgd, ihnp4, rutgers}!
~ Oklahoma State University                   okstate!garnett

henry@utzoo.uucp (Henry Spencer) (12/06/88)

In article <122@rdahp.UUCP> geoff@rdahp.UUCP (Geoff Walsh) writes:
>#define diagprintf(TestCriteria,TestLevel,Fmt) \
>    #if (TestCriteria >= TestLevel)\
>        printf s\
>    #endif
>
>    1.  Is there any portable, standard way to do something like this with
>        the preprocessor?

Try:

#if TestCriteria >= TestLevel
#define diagprintf(TestCriteria,TestLevel,Fmt) ... /* whatever */
#else
#define diagprintf(TestCriteria,TestLevel,Fmt) 	/* nothing */
#endif

>    2.  Is this legit in ANSI C and do I need to just wait for the
>        next version of my compiler? ...

No.  Putting preprocessor directives inside a macro explicitly does not
work in ANSI C.
-- 
SunOSish, adj:  requiring      |     Henry Spencer at U of Toronto Zoology
32-bit bug numbers.            | uunet!attcan!utzoo!henry henry@zoo.toronto.edu