tags:

views:

150

answers:

6

Hi everyone. 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.

A: 

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.

GMan
This is wrong. If you define `DEBUG_IF(x)` to be blank in the absence of the `DEBUG` symbol, then `DEBUG_IF(foo) { bar }` becomes `{ bar }` which always executes.
Tyler McHenry
Without `DEBUG`, it will be as though the condition were always `true`, i.e. the block will be executed. This is not what the OP asked for.
Thomas
The OP's question is not clear to me, then. `DEBUG_IF( rv==false )` suggests only one thing to me...
GMan
I understood the question to be "how do I make a macro so that if `DEBUG` is defined *and* the condition is true, the block executes?" because that describes the behavior of his first snippet.
Tyler McHenry
@Tyler: Does it? His first snippet isn't real code. How did you manage to pull real code out if it? The `#endif` could go anywhere. Since his second example only surrounds the if with the macro, I used that as reason to believe you intended for the end if to have been after the if in the first example, plus that matches the question in the title. He should edit and clarify so we know.
GMan
@GMan: Have another look at the first code block then. But your answer is better now; removed the downvote :)
Thomas
@Thomas: What am I looking for? Also, read the text itself: "I need some help in writing a macro for 'if-condition' which compiles only when a DEBUG flag is defined by the #define directive." Only the if-condition, not the entire block. Though such a trivial question might also correlate with poor terminology... Also, @Tyler: You do realize on your first comment *I* explained that within my post?
GMan
If the statement includes an 'ELSE' clause, it will fail to compile when DEBUG isn't defined.
Kelly French
+7  A: 

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.

Tyler McHenry
"may later be optimized out" -> "*will* be optimized out". There's no way to undersell it and make the OP doubt that the compiler performs trivial optimizations.
jalf
Every compiler on earth under every possible set of flags always does dead code elimination? I doubt that.
Tyler McHenry
Anyway, my point was that the code inside the `if` block must be valid, compilable code when using this macro, since it is compiled even if eliminated, whereas with the straight `#ifdef` the code could contain errors which would not be detected so long as `DEBUG` remained undefined.
Tyler McHenry
I might suggest 'will probably' instead of 'may'.
Craig Trader
@Tyler: Depends. Typically, if performance or memory footprint is of any concern, you'll use a compiler that has at least minimal optimization. A compiler with minimal optimization will usually eliminate that code. Under most circumstances, it's not something to worry about. The exception would be when using a really bad compiler on some really obscure system, and that really doesn't come up much.
David Thornley
It will probably eliminate it, but it's still necessary that the code within the following block be well formed. You can't for example use a type or functions that's only defined in debug mode...
Matthieu M.
@Tyler: No, probably not, but I'm willing to bet that it'll happen with the compiler used by the OP, and the compilation flags used. It is such an extremely fundamental optimization that there's no point in giving the OP the impression that "if you're lucky, it might not cost anything". In practical terms, on real-world non-toy compilers, it is going to be optimized away.
jalf
+2  A: 

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.

Mark Rushakoff
Wouldn't you want the ELSE block to be always included/excluded along with the state of the #DEBUG macro? The OP is unclear on this.
Kelly French
A: 

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.

Void
A: 

IMHO, the best approach is

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

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.