35

I'm trying to do a debug system but it seems not to work.

What I wanted to accomplish is something like this:

#ifndef DEBUG
    #define printd //
#else
    #define printd printf
#endif

Is there a way to do that? I have lots of debug messages and I won't like to do:

if (DEBUG)
    printf(...)

code

if (DEBUG)
    printf(...)

...
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Ben B.
  • 353
  • 1
  • 3
  • 6
  • 1
    Direct duplicate of http://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing/1644898#1644898 and probably others too. – Jonathan Leffler Nov 23 '09 at 19:45
  • 4
    @JonathanLeffler the *use case* (creating a debug-only print macro) is a duplicate of http://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing/1644898#1644898, but the literal question asked (can I include `//` in a `#define`) is not - and the literal question asked is interesting and useful to others. The overlap is unfortunate, but there's a distinct question here which has value; it shouldn't be closed. – Mark Amery Dec 27 '15 at 11:39
  • @MarkAmery: The title is an ['XY Problem'](http://www.perlmonks.org/?node_id=542341) — the solution to what the user is trying to achieve is in the nominated duplicate, but the question is asking for something tangential which won't even achieve what they want. – Jonathan Leffler Dec 27 '15 at 17:24
  • 2
    @JonathanLeffler whether you think the title is problematic or not, I would simply not have found these answers or thought of doing things a certain way if I haven't clicked this title in the Google search results. For me the questions was more about how to strip code out of production without needing `#ifdefs` everywhere, and thanks to OP's tangential question I found ideas that set me on the right track. I would not have searched for a question on "debug printing"--that's simply not my use case! – Username Obfuscation May 28 '18 at 03:35

12 Answers12

36

No, you can't. Comments are removed from the code before any processing of preprocessing directives begin. For this reason you can't include comment into a macro.

Also, any attempts to "form" a comment later by using any macro trickery are not guaranteed to work. The compiler is not required to recognize "late" comments as comments.

The best way to implement what you want is to use macros with variable arguments in C99 (or, maybe, using the compiler extensions).

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
25

A common trick is to do this:

#ifdef DEBUG
  #define OUTPUT(x) printf x
#else
  #define OUTPUT(x)
#endif

#include <stdio.h>
int main(void)
{   
  OUTPUT(("%s line %i\n", __FILE__, __LINE__));

  return 0;
}

This way you have the whole power of printf() available to you, but you have to put up with the double brackets to make the macro work.

The point of the double brackets is this: you need one set to indicate that it's a macro call, but you can't have an indeterminate number of arguments in a macro in C89. However, by putting the arguments in their own set of brackets they get interpreted as a single argument. When the macro is expanded when DEBUG is defined, the replacement text is the word printf followed by the singl argument, which is actually several items in brackets. The brackets then get interpreted as the brackets needed in the printf function call, so it all works out.

Tim
  • 9,171
  • 33
  • 51
20

С99 way:

#ifdef DEBUG
    #define printd(...) printf(__VA_ARGS__)
#else
    #define printd(...)
#endif

Well, this one doesn't require C99 but assumes compiler has optimization turned on for release version:

#ifdef DEBUG
    #define printd printf
#else
    #define printd if (1) {} else printf
#endif
Xeor
  • 1,846
  • 1
  • 12
  • 12
  • Correct, but not quite portable. – Tim Post Nov 23 '09 at 19:04
  • Much better, but again the "portable" version does not disable the validity checks on the arguments. The proper way to do it in non-C99 implementation is given in Tim's answer. – AnT stands with Russia Nov 23 '09 at 19:15
  • And that's its good side I think. Why disable validity check on code that will be real in debug versions? – Xeor Nov 23 '09 at 19:15
  • Simple: because that code might be invalid in release versions. There's nothing wrong with debug code being invalid in release. Moreover, that's the way it is most of the time. – AnT stands with Russia Nov 23 '09 at 19:19
  • 2
    @AndreyT: Even though this question is quite old and has already been answered I'm intrigued with your comment. Could you provide or point to an example where debug code might be invalid in release versions? Thank you very much. – Carla Álvarez Jan 21 '10 at 14:21
  • @CarlaÁlvarez the case I have seen numerous times where debug code is invalid in release versions is for debug tracking variables that simply do not exist in release code. You couldn't have a printf that references the debug variables that won't exist in release code, and you do not want the extra variables taking up space in release code. – piCookie Jun 16 '22 at 15:33
10

On some compilers (including MS VS2010) this will work,

#define CMT / ## /

but no grantees for all compilers.

Cody
  • 2,643
  • 2
  • 10
  • 24
Igor Barbarian
  • 131
  • 2
  • 7
8

You can put all your debug call in a function, let call it printf_debug and put the DEBUG inside this function. The compiler will optimize the empty function.

slurdge
  • 423
  • 3
  • 8
2

The standard way is to use

#ifndef DEBUG
    #define printd(fmt, ...)  do { } while(0)
#else
    #define printd(fmt, ...) printf(fmt, __VA_ARGS__)
#endif

That way, when you add a semi-colon on the end, it does what you want. As there is no operation the compiler will compile out the "do...while"

Dipstick
  • 9,854
  • 2
  • 30
  • 30
1

In C++17 I like to use constexpr for something like this

#ifndef NDEBUG
constexpr bool DEBUG = true;
#else
constexpr bool DEBUG = false;
#endif

Then you can do

if constexpr (DEBUG) /* debug code */

The caveats are that, unlike a preprocessor macro, you are limited in scope. You can neither declare variables in one debug conditional that are accessible from another, nor can they be used at outside function scopes.

  • 3
    This is not an answer, question is tagged C, and answer is for C++. Those are two different languages. – SergeyA Jun 07 '18 at 18:04
1

You can take advantage of if. For example,

#ifdef debug
    #define printd printf
#else 
    #define printd if (false) printf
#endif

Compiler will remove these unreachable code if you set a optimization flag like -O2. This method also useful for std::cout.

1

Untested: Edit: Tested, using it by myself by now :)

#define DEBUG 1
#define printd(fmt,...) if(DEBUG)printf(fmt, __VA_ARGS__)

requires you to not only define DEBUG but also give it a non-zer0 value.

Appendix: Also works well with std::cout

drahnr
  • 6,782
  • 5
  • 48
  • 75
0

As noted by McKay, you will run into problems if you simply try to replace printd with //. Instead, you could use variadric macros to replace printd with a function that does nothing as in the following.

#ifndef DEBUG
    #define printd(...) do_nothing()
#else
    #define printd(...) printf(__VA_ARGS__)
#endif

void do_nothing() { ; }

Using a debugger like GDB might help too, but sometimes a quick printf is enough.

Swiss
  • 5,556
  • 1
  • 28
  • 42
0

I use this construct a lot:

#define DEBUG 1
#if DEBUG
#if PROG1
#define DEBUGSTR(msg...)        { printf("P1: "); printf( msg); }
#else
#define DEBUGSTR(msg...)        { printf("P2: "); printf( msg); }
#endif
#else
#define DEBUGSTR(msg...)    ((void) 0)
#endif

This way I can tell in my console which program is giving which error message... also, I can search easily for my error messages...

Personally, I don't like #defining just part of an expression...

Brian Postow
  • 11,709
  • 17
  • 81
  • 125
0

It's been done. I don't recommend it. No time to test but the mechanism is kind of like this:

 #define printd_CAT(x) x ## x
 #ifndef DEBUG
    #define printd printd_CAT(/)
 #else
    #define printd printf
 #endif

This works if your compiler processes // comments in the compiler itself (there's no guarantee like the ANSI guarantee that there are two passes for /* comments).

Joshua
  • 40,822
  • 8
  • 72
  • 132