4

I am trying to create a macro that executes blocks of code only if it's a debug build. I've managed to make one that executes one line only if debug is enabled, but i cannot figure out how to do a whole block of code.

the one line macro is below:

#include <iostream>

//error checking
#if defined(DEBUG) | defined(_DEBUG)
    #ifndef DBG_ONLY
         #define DBG_ONLY(x) (x)            
    #endif
#else
    #ifndef DBG_ONLY
        #define DBG_ONLY(x) 
    #endif
#endif 



int main () {

    DBG_ONLY(std::cout << "yar" << std::endl);
    return 0;


}
EvilTeach
  • 28,120
  • 21
  • 85
  • 141
r m
  • 177
  • 13
  • 1
    I am not in a position to test code, but shouldn't your or operator be || rather than | – EvilTeach Jan 03 '13 at 01:52
  • 2
    @EvilTeach: normally, you use `||` rather than just `|`, but both work. – Jonathan Leffler Jan 03 '13 at 01:55
  • 1
    http://stackoverflow.com/questions/7372448/c-macro-to-conditionally-compile-code?rq=1 This is a dupe, but i think purreals answer is better. – EvilTeach Jan 03 '13 at 02:03
  • See the answer to [C `#define` macro for debug printing](http://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing/). It is very closely related, though not identical. In particular, note the commentary about 'ensuring the code is always compiled' (even if it is not included in the object file). It is even more important with bigger blocks of code; they are more likely to be out of sync with their surroundings. – Jonathan Leffler Jan 03 '13 at 02:09

2 Answers2

6

Wrap the macro inside a do-while loop so that you avoid problems when using your macro in conditional statements such as if (cond) DBG_ONLY(i++; j--;). It also creates a new scope for debug only declarations:

#if defined(DEBUG) | defined(_DEBUG)
    #ifndef DBG_ONLY
      #define DBG_ONLY(x) do { x } while (0)         
    #endif
#else
    #ifndef DBG_ONLY
      #define DBG_ONLY(x) 
    #endif
#endif 

int main () {
    DBG_ONLY(
        std::cout << "yar" << std::endl;
        std::cout << "yar" << std::endl;
        std::cout << "yar" << std::endl;
        std::cout << "yar" << std::endl;
        );
    return 0;
}

This will fail if you have statements like int i,j. For that, we need a variadic macro I guess:

#if defined(DEBUG) | defined(_DEBUG)
    #ifndef DBG_ONLY
      #define DBG_ONLY(...) do { __VA_ARGS__; } while (0)
    #endif
#else
    #ifndef DBG_ONLY
      #define DBG_ONLY(...) 
    #endif
#endif 
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
perreal
  • 94,503
  • 21
  • 155
  • 181
  • Good catch, comma in function calls is OK – perreal Jan 03 '13 at 01:41
  • it might be a good idea to comment on why the do while is needed. – EvilTeach Jan 03 '13 at 01:55
  • 2
    This also has the effect of creating a new inner scope, which may or may not be a good thing... – Oliver Charlesworth Jan 03 '13 at 01:57
  • for the purposes of debugging i would expect the scope to not matter. – EvilTeach Jan 03 '13 at 02:00
  • @EvilTeach: But what about things like `DBG_ONLY(int debug_var = 5;) some_other_code(); DBG_ONLY(foo(debug_var);)`? – Oliver Charlesworth Jan 03 '13 at 02:04
  • I suspect that if you start doing that sort of thing, we would be likely to fall upon you, in the biblical sense. The OP seems to indicate in his example that it is for debug messages. The case you are citing should not come up. – EvilTeach Jan 03 '13 at 02:07
  • 1
    @EvilTeach: Hmm, that's a bit of an assumption. I have frequently added debug code that reports the number of times that a bit of code has been iterated through, for instance. That requires debug code "scattered" across a function. – Oliver Charlesworth Jan 03 '13 at 02:08
  • Yep. Your point is valid. I don't use the technique. I prefer having a global int to hold the debug status. (i write monolithic apps) so the users can turn on the debug from the command line. To each cat its own rat. – EvilTeach Jan 03 '13 at 02:12
  • 2
    Note that the `#define DBG_ONLY(x...)` notation is not standard C but a GCC extension. For standard C, you would probably use just `#define DBG_ONLY(...) if (debugging) do { __VA_ARGS__; } while (0)`, where `debugging` is a constant that determines whether the debugging code is included. This will ensure that the compiler always checks the code (very important) but it will only be included in the object file when `debugging` evaluates to true. – Jonathan Leffler Jan 03 '13 at 02:15
4

If this is for "arbitrary" debug code (as opposed to strictly logging), then one crude option is a straightforward #if/#endif.

#if defined(DEBUG) | defined(_DEBUG)
    #define DBG_ONLY
#endif 

...    

#ifdef DBG_ONLY
    // Blah blah blah
#endif

This is definitely uglier than @perreal's solution, but it avoids any of the scoping issues, and works in all language variants (and any other issues we haven't yet thought about!).

It's also true that it's conditional code, and so has the possibility of getting badly out of sync (because it's not always checked by the compiler). But this is also true of the macro solution.

There is one other advantage; in a decent IDE (e.g. Eclipse CDT), your debug code will be highlighted differently.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • i'd really rather not use preproccessor directives all over my code if possible – r m Jan 03 '13 at 01:36
  • 1
    Fair enough. Not sure why this is being down voted though, a macro is equivalent to a directive... – Oliver Charlesworth Jan 03 '13 at 01:39
  • @OliCharlesworth I think your objection is perfectly reasonable. Depends on the actual code, but I also think in practical problems `#if / #endif` should be preferred. Maybe you can edit your answer to make your intention clearer. – Philipp Claßen Jan 03 '13 at 02:03
  • I think it was downvoted because (although your point was indeed valid) it didn't address the original question, instead bringing in a question of style. – HerrJoebob Jan 03 '13 at 06:47