39

in C, what is the proper way to define a printf like macro that will print only when DEBUG symbol is defined?

#ifdef DEBUG
#define DEBUG_PRINT(???) ???
#else
#define DEBUG_PRINT(???) ???
#endif

where ??? is where I am not sure what to fill in

jww
  • 97,681
  • 90
  • 411
  • 885
John
  • 391
  • 1
  • 3
  • 3
  • 5
    Dupe of http://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing among many others. –  Dec 21 '09 at 17:04
  • 1
    has been asked before; link to my answers: http://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing/1645152#1645152 – Christoph Dec 21 '09 at 17:04
  • 3
    Possible duplicate of [C #define macro for debug printing](https://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing) – Tim Nov 10 '18 at 23:26

8 Answers8

47

I've seen this idiom a fair amount:

#ifdef DEBUG
# define DEBUG_PRINT(x) printf x
#else
# define DEBUG_PRINT(x) do {} while (0)
#endif

Use it like:

DEBUG_PRINT(("var1: %d; var2: %d; str: %s\n", var1, var2, str));

The extra parentheses are necessary, because some older C compilers don't support var-args in macros.

Aidan Cully
  • 5,457
  • 24
  • 27
  • Thanks for the annotation about the extra parentheses. – kazbeel May 11 '16 at 11:22
  • I see some minor errors in your implementation (missing parenthesis around `x`, for instance, and not using `__VA_ARGS__`). [So, here is my approach, based on yours](https://stackoverflow.com/a/67667132/4561887). – Gabriel Staples May 24 '21 at 05:43
  • 1
    @GabrielStaples This answer intends to explain very old code, that predates the `__VA_ARGS__` based approach. In code less than 20 years old, you should certainly prefer `__VA_ARGS__`. – Aidan Cully Jun 06 '21 at 18:20
29
#ifdef DEBUG
#define DEBUG_PRINT(...) do{ fprintf( stderr, __VA_ARGS__ ); } while( false )
#else
#define DEBUG_PRINT(...) do{ } while ( false )
#endif
moonshadow
  • 86,889
  • 7
  • 82
  • 122
22

Something like:

#ifdef DEBUG
#define DEBUG_PRINT(fmt, args...)    fprintf(stderr, fmt, ## args)
#else
#define DEBUG_PRINT(fmt, args...)    /* Don't do anything in release builds */
#endif
mipadi
  • 398,885
  • 90
  • 523
  • 479
22

Thank you mipadi, I improved your DEBUG_PRINT with file information too.

#define DEBUG 3

#if defined(DEBUG) && DEBUG > 0
 #define DEBUG_PRINT(fmt, args...) fprintf(stderr, "DEBUG: %s:%d:%s(): " fmt, \
    __FILE__, __LINE__, __func__, ##args)
#else
 #define DEBUG_PRINT(fmt, args...) /* Don't do anything in release builds */
#endif

Tested with latest clang, e.g.

int main(int argc, char **args) {
    DEBUG_PRINT("Debugging is enabled.\n");    
    DEBUG_PRINT("Debug level: %d", (int) DEBUG);
}

outputs:

DEBUG: debug.c:13:main(): Debugging is enabled.
DEBUG: debug.c:14:main(): Debug level: 3
Tom Kuschel
  • 695
  • 8
  • 19
4

Use different signatures of DEBUG_PRINT, they don't have to be the same, like:

#ifdef DEBUG
#define DEBUG_PRINT printf
#else
#define DEBUG_PRINT(...)
#endif

this way on debug mode the DEBUG_PRINT call will be replaced with printf. On release it will ignore all arguments used previously.

Hope it helps.

Sérgio
  • 149
  • 4
2

You can simply use:

#ifdef DEBUG
    #define DEBUG_PRINT printf
#else
    #define DEBUG_PRINT
#endif
Echilon
  • 10,064
  • 33
  • 131
  • 217
Sorin
  • 37
  • 1
  • if you have code like this `if(x) DEBUG_PRINT("SOME DEBUG");` then this does not work. – Raj Jan 30 '13 at 13:53
0

I like this way the best because it wont add any asm instructions to your release build.

#define DEBUG
#ifdef DEBUG
#define  debug_printf(fmt, ...)  printf(fmt, __VA_ARGS__);
#else
#define debug_printf(fmt, ...)    /* Do nothing */
#endif
0

This works in both C and C++! (Note that the space before __VA_ARGS__ is required for it to work in C++!)

I see some minor errors in the implementation in the main answer. So, here is my approach:

#ifdef DEBUG
    #define DEBUG_PRINTF(...) printf("DEBUG: " __VA_ARGS__)
#else
    #define DEBUG_PRINTF(...) do {} while (0)
#endif

Example usage:

DEBUG_PRINTF("hello\n");

Then, if I build and run with the -DDEBUG define on in my C build options, like this:

# Build
gcc -Wall -Wextra -Werror -std=c11 -DDEBUG -o build/my_program \
my_program_tests.c my_program.c

# Run
build/my_program

then I see this output:

DEBUG: hello

But if I build withOUT the -DDEBUG define in my compiler C options, then I see no debug prints whatsoever.

Other references

  1. The fix to make this compatible with C++ too: https://stackoverflow.com/a/72777133/4561887: add a space before __VA_ARGS__. Use "DEBUG: " __VA_ARGS__ instead of "DEBUG: "__VA_ARGS__!
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265