1

I have a macro:

#define debug(fmt, ...) printf("%lu %s:%s:%i " fmt, ms(), __FILE__, __func__, __LINE__, __VA_ARGS__)

which does just what I want.

I can call it with:

debug("i: %i\n", i);

to print the value of i.

My problem is that I can't call it with:

debug("got here");

as that expands to:

printf("%lu %s:%s:%i %s " "got here", ms(), __FILE__, __func__, __LINE__,)

which is a trailing-comma bug.

How can I change my __VA_ARGS__ macro so that it can handle the "no variables"/"only format string" case?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
fadedbee
  • 42,671
  • 44
  • 178
  • 308

2 Answers2

2

You can do it in two steps:

#define debug(...) DEBUG(__VA_ARGS__, "")
#define DEBUG(fmt, ...) printf("%lu %s:%s:%i " fmt "%s", ms(), __FILE__, __func__, __LINE__, __VA_ARGS__)

debug("%d\n", 42);
debug("Hello\n");

In this way, even if you don't pass a second param it is replaced by an "" and results in a NOP.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
David Ranieri
  • 39,972
  • 7
  • 52
  • 94
2

Instead of trying to concatenate string literals in the macro itself, you can split the printf into two parts: One for the statistics, the other for your debug message. Yoke them together with the old do { ... } while (0) macro trick.

#define debug(...) do {                                                 \
        printf("%lu %s:%s:%i ", ms(), __FILE__, __func__, __LINE__);    \
        printf(__VA_ARGS__);                                            \
    } while (0)

Then you don't need the fmt as separate argument and can just pass __VA_ARGS__ to the second printf.

M Oehm
  • 28,726
  • 3
  • 31
  • 42
  • 3
    In a multi-threaded program, this opens up the possibility of two threads interfering with each other — whereas a single call to `printf()` ensures that does not happen. POSIX provides [`flockfile()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.html) and `funlockfile()` to allow grouping of separate operations — so adding `flockfile(stdout);` before the first `printf()` and `funlockfile()` after the second would ensure that other threads do not split the message. – Jonathan Leffler May 27 '20 at 13:36