简体   繁体   中英

Why doesn't my simple C macro work?

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?

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.

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM