Why doesn't my simple C macro work?

2019-08-02 17:39发布

问题:

I want to make a simple macro that calls printf() twice like this

#ifdef ENABLE_DEBUGPRINTF
#define DEBUGPRINTF(msg) printf("At sim_time = %f:", sim_time); printf(msg);
#else
#define DEBUGPRINTF(msg)  //evalutes to nothing
#endif

Now when I call

DEBUGPRINTF("Processed event type: %d with value %f\n", id, data)

It prints the first part "At sime_time = ... " correctly but the latter part where it says "Processed events ... " prints the value for id and data incorrectly.

Meanwhile

printf("Processed event type: %d with value %f\n", id, data);

Prints the values correctly.

When I try executing it by writing exactly out what I thought the macro would evaluate to, I have.

printf("At sim_time = %f:", sim_time); printf("Processed event type: %d with value %f\n", id, data);

This prints everything correctly! So why isn't my macro evaluating to this?

回答1:

Because you want and are using the full flexibility of a regular printf, what you want is a macro with a variadic argument:

#ifdef ENABLE_DEBUGPRINTF
#define DEBUGPRINTF(msg...) \
    printf("At sim_time = %f:", sim_time); printf(msg);
#else
#define DEBUGPRINTF(msg...)  /*evalutes to nothing*/
#endif

I've done this many times before and I recommend encapsulating with do { } while (0):

#ifdef ENABLE_DEBUGPRINTF
#define DEBUGPRINTF(msg...) \
    do { \
        printf("At sim_time = %f:", sim_time); \
        printf(msg); \
    } while (0)
#else
#define DEBUGPRINTF(msg...)  //evalutes to nothing
#endif

This allows you to do something like:

if (showit)
    DEBUGPRINTF("hit the showit point -- showit=%d\n",showit);

Thus, the code that uses the macro doesn't have to know that it's actually two statements [or none]


UPDATE:

DEBUGPRINTF(msg...) is not standard compliant, but some legacy compiler extension. You missed a comma before the ellipsis.

Perhaps, but, personally, I still prefer it, and have been using it in production code for 10+ years.

However, here are some resources for those that might wish to use the alternative ways:

  1. https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
  2. https://en.wikipedia.org/wiki/Variadic_macro


回答2:

You declare DEBUGPRINTF as taking one argument, but then you pass it three, so of course it's not working as you'd expect.

msg is just "Processed event type: %d with value %f\n" in your first example, and your second printf() call is just pulling garbage for the %d and the %f, because your macro never tells it anything about id or data and so they never get passed to printf().

You want something like:

#define DEBUGPRINTF(msg, id, data) printf("At sim_time = %f:", sim_time); printf(msg, id, data);

or, if you need something more flexible, to play around with variadic macros.



回答3:

Use a double ( nested) definition:

#define FIRST         printf("…")
#define DEBUGMSG(msg) FIRST;printf(msg)

This has one argument in definition, and one argument in implementation.