And Or
And Or

Reputation: 59

How to write an 'if' condition that compiles only when DEBUG is #defined?

I need some help in writing a macro for 'if-condition' which compiles only when a DEBUG flag is defined by the #define directive.

Here is an example which illustrates what I want. first piece of code shows the usual way of writing an if condition with a #ifdef.

#ifdef DEBUG
if( rv == false )
{
     string errorStr = "error in return value" ;
     cout << errorStr << endl ;
     throw( Exception(errorStr) ) ;
}

I want to write it in a way similar as below:

DEBUG_IF( rv==false )
{
     same code as above
}

It seems to be simple but I am having trouble defining a macro which can do this. If someone has experienced this before, kindly help.

Thanks.

Upvotes: 4

Views: 10074

Answers (7)

Tim
Tim

Reputation: 413

Somewhat late here but I was wondering whether simply defining a constant may be more elegant than defining a function:

#ifdef DEBUG
    #define IS_IN_DEBUG true
#else
    #define IS_IN_DEBUG false
#endif

if ( IS_IN_DEBUG ) {
  // do something
}

Isn’t this easier to read? Any thoughts on this?

Upvotes: 0

stinky472
stinky472

Reputation: 6797

I don't recommend using a DEBUG_IF kind of macro for the reason Kelly pointed out.

DEBUG_IF(x)
{
    // debugging code
}
else
{
    // release code (should be executed for both debug and release)
}

See the logical error here? The release code should always be executed unless it's release-only code, yet this would be a fairly easy mistake to make with the DEBUG_IF macro. It might be a nuisance to write this out, but I think it's the clearest and least confusing way. If you do use it, I recommend avoiding else with it completely.

The same is true of the DEBUG_CONDITION macro.

if (DEBUG_CONDITION(x) )
{
    // debugging code
}
else
{
    // oops, this never gets executed in debug builds
}

Release-only code is very rare in contrast to debug-only code so these kinds of occurrences would generally be logical errors. When I started using C++ I wanted to shorthand everything, but I've learned over the years and especially from working with a team that it's generally better to write it out as intended. Strive to achieve conciseness in logic, but you have to be careful not to cross a line where reducing code steps into obfuscation boundaries.

The idea of debugging a large-scaled system filled with DEBUG_IF/DEBUG_CONDITION macros like these gives me a splitting headache.

Upvotes: 0

edef
edef

Reputation: 752

IMHO, the best approach is

#ifdef DEBUG
if(blah){
    dostuff();
}
#endif

Upvotes: 1

Void - Othman
Void - Othman

Reputation: 3481

Personally I'd go with the #ifdef DEBUG route instead of the code obfuscating DEBUG_IF macro approach. Better to write clear code that doesn't hide code behind some macro.

If you really want to go the macro route, I'd leave the if alone and focus on the condition itself, e.g.

#ifdef DEBUG
# define DEBUG_CONDITION(x) x
#else
# define DEBUG_CONDITION(x) false
#endif  /* DEBUG */

if (DEBUG_CONDITION(rv == false))
{
   ...
}

Some obfuscation still exists with this approach but it is, IMHO, more acceptable than the proposed DEBUG_IF() macro since it preserves C/C++ syntax.

I believe most, if not all, compilers will simply optimize out the dead code resulting from the if(false) in the non-DEBUG case (e.g. equivalent to if(0)). However, some compilers could conceivably issue a "dead code" warning with this approach as well as the DEBUG_IF() approach you described.

Upvotes: 0

Tyler McHenry
Tyler McHenry

Reputation: 76690

Try:

#ifdef DEBUG
  #define DEBUG_IF(x) if(x)
#else
  #define DEBUG_IF(x) if(false)
#endif

Now this won't be exactly the same as what you have right now, because when using this method, the code inside the if block still gets compiled, although it will never be run when DEBUG is not defined, and will probably be optimized out. In contrast, with your original example, the code is eliminated by the preprocessor and is never even compiled.

Upvotes: 9

GManNickG
GManNickG

Reputation: 503963

Do you want the if to be conditional, so that in Release the code runs unconditionally? (As the title suggests.) Or do you want the entire block to be conditional? (So it Release there is no block.) You're missing the #endif in your equivalence code so it's impossible to tell.

For the former, you could use this:

#ifdef DEBUG
    #define DEBUG_IF(x) if (x)
#else
    #define DEBUG_IF(x) if (false)
#endif

The code in the block will be compiled, but discarded by the compiler, as it's dead code. If you only want the conditional to be changed, do this:

#ifdef DEBUG
    #define DEBUG_IF(x) if (x)
#else
    #define DEBUG_IF(x)
#endif

Without DEBUG, the entire conditional ceases to exist. Fix your question to make it clear what you want.

Upvotes: 0

Mark Rushakoff
Mark Rushakoff

Reputation: 258238

I think this is what you're looking for:

#include <iostream>

#ifdef DEBUG
#define DEBUG_IF(cond) if(cond)
#else
#define DEBUG_IF(cond) if(false)
#endif

int main(int argc, char** argv)
{
  DEBUG_IF(argc > 1)
  {
     std::cout << "In debug mode and at least one argument given" << std::endl;
  }
  else
  {
    std::cout << "Not in debug mode or no arguments given" << std::endl;
  }
}

Run this at the command line, with or without an argument, with or without being compiled with -DDEBUG for proof that it works as expected.

Upvotes: 2

Related Questions