1

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?

jezzi23
  • 250
  • 4
  • 12
  • @PaulGriffiths D'oh of course. Sorry, I'm not used to pre-processor directives. For some reason I imaged everything inside the parenthesis would be contained in 'msg'. – jezzi23 Apr 02 '16 at 21:35
  • 2
    Unrelated, but it's best to put braces around a multi-instruction macro like this: `#define DEBUGPRINTF(msg, id, data) { etc... }`. Otherwise you could get some surprises when, for example, the macro is used after a `if`. – Unimportant Apr 02 '16 at 21:45
  • 2
    @user1320881: That still will result in wrong code, e.g. in an `if` statement. The common way to do it correctly is wrap into a `do .. while ( 0 )` dummy-loop. Every modern compiler will recognise this pattern and optimise-aways the loop. – too honest for this site Apr 02 '16 at 22:02
  • @Olaf: In this case, since the `printf` calls are expressions, it's even better to separate them with a comma operator and enclose the whole thing in parentheses (and drop the semicolons). The `do ... while(0)` trick let's you use the macro anywhere a statement is expected, but if the expansion is an expression it's even more flexible. – Keith Thompson Apr 02 '16 at 23:55

3 Answers3

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.

Crowman
  • 25,242
  • 5
  • 48
  • 56
2

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
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
-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.

Arif Burhan
  • 507
  • 4
  • 12
  • This does nothing more than what the OP already has. It does not resolve the OP's actual question at all. If you try `DEBUGPRINTF("Processed event type: %d with value %f\n", id, data)` as the OP wants then you will find your solution will fail in exactly the same way as the OP is experiencing. – kaylum Apr 02 '16 at 21:45