jezzi23
jezzi23

Reputation: 250

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?

Upvotes: 1

Views: 313

Answers (3)

Craig Estey
Craig Estey

Reputation: 33601

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

Upvotes: 2

Arif Burhan
Arif Burhan

Reputation: 505

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.

Upvotes: -3

Crowman
Crowman

Reputation: 25908

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.

Upvotes: 2

Related Questions