views:

398

answers:

6
+6  Q: 

#if 0 as a define

I need a way to define a FLAGS_IF macro (or equivalent) such that

FLAGS_IF(expression)
<block_of_code>
FLAGS_ENDIF

when compiling in debug (e.g. with a specific compiler switch) compiles to

if (MyFunction(expression))
{
    <block_of_code>
}

whereas in release does not result in any instruction, just as it was like this

#if 0
    <block_of_code>
#endif

In my ignorance on the matter of c/c++ preprocessors i can't think of any naive way (since #define FLAGS_IF(x) #if 0 does not even compile) of doing this, can you help?

I need a solution that:

  • Does not get messed up if */ is present inside <block_of_code>
  • Is sure to generate 0 instructions in release even inside inline functions at any depth (i guess this excludes if (false){<block_of_code>} right?)
  • Is standard compliant if possible

Thank you

+1  A: 

How about something like this:

#ifdef DEBUG
#define FLAGS_IF(expr, block) { if (MyFunction(expr)) block }
#else
#define FLAGS_IF(expr, block)
#endif

You can use it like this:

FLAGS_IF(your_favourite_expression,
  ({
     // some code
  })
)
Carl Norum
Yes, this is how I would do it
joveha
I have done this and syntax highlighters choke. Oh well.
Joshua
Hm, works ok in SlickEdit for me; haven't tried many others.
Carl Norum
Fails because it's not parsed as you'd like: http://codepad.org/2zKnbtkR
Roger Pate
I prefer not to enclose the block as a macro argument, yet thanks
valerio
+3  A: 

Why can't you use the following?

#ifdef DEBUG
code for debug mode
#else
code for release mode
#endif
atk
I don't like this because it requires a lot of code replication, i prefer putting the switching logic inside the macro
valerio
I'm not really clear on how this is any different from using a macro. Whether you #ifdef DEBUG or you use an actual macro, it seems like you're going to have almost the exact same amount of duplication. And using the #ifdef DEBUG is a more common way of doing it, so it's more likely people will know exactly what you're doing more quickly, rather than creating a maintenance issue.
atk
+7  A: 

The following should do what you want:

#ifdef DEBUG
# define FLAGS_IF(x) if (MyFunction((x))) {
# define FLAGS_ENDIF }
#else
# define FLAGS_IF(x) if(0) {
# define FLAGS_ENDIF }
#endif

The if(0) should turn into no instructions, or at least it does so on most compilers.

Edit: Hasturkun commented that you don't really need the FLAGS_ENDIF, so you would instead write your code like this:

FLAGS_IF(expression) {
   <block_of_code>
}

with the follow macros:

#ifdef DEBUG
# define FLAGS_IF(x) if (MyFunction((x)))
#else
# define FLAGS_IF(x) if(0)
#endif
bramp
I am guessing that valerio is looking for a simple way to enable/disable more than just one function. Your solution is not scalable and hides the real implementation. The solution for this problem is using plain ifdef.
eyalm
If that's the case i don't really need a FLAGS_IF macro that hides the if statement.I can just use #define FLAGS_EXP(expression) 0if (FLAGS_EXP(expression)){ <block_of_code>}
valerio
+22  A: 

Macros are pretty evil, but there's nothing more evil than obfuscating control statements and blocks with macros. There is no good reason to write code like this. Just make it:

#ifdef DEBUG
  if (MyFunction(expression))
  {
    <block_of_code>
  }
#endif
Hans Passant
I completely agree but i can't afford to do this every time. A macro in this case is pretty useful
valerio
I don't think this solution is any different than the one you accepted in terms of typing.
Carl Norum
The other one allows me to enclose the #ifdef inside the condition
valerio
I'll give this one more shot. The problem with macros like this is that you create your own language. It is a language that somebody that maintains your code is going to have to learn without the benefit of a book or a school. Much more seriously, it is a language that you don't parse yourself. You cannot create good error messages that helps somebody troubleshoot a problem when the macro blows up. It looks attractive now, it will be a major pita later. And it *will* blow up.
Hans Passant
I guess you need to have encountered the "augmented C/C++ codebase from hell" in person to realize the depth of nobugz's comment here. I can vouch he is all too right. And the macros I have seen firsthand were neither more nor less gratuitous than debug blocks.
Pascal Cuoq
Two independent examples: the first example had `#define ENDFOR }`, you can extrapolate from there to other control structures and see how that both could be incredibly stupid and plausibly seem like a good idea to someone at the time. The second example was a set of macros to insert in the .C file to generate the .H file automatically. Again, seems like a good idea, but not worth the trouble (any .C file change generated a new .H so separate compilation was effectively lost, ...)
Pascal Cuoq
+6  A: 

I might do something like:

#ifdef DEBUG
const bool IS_RELEASE_MODE = false;
#else
const bool IS_RELEASE_MODE = true;
#endif

if (IS_RELEASE_MODE && MyFunction(expression))
{
    ...
}

This should get compiled out of release builds due to the fact that if (false && f()) is the same as if (false), which gets optimized out in most compilers.

That's if you're insistent on not using #ifdef on the inside of your code. Otherwise, I'd prefer the #ifdef DEBUG if (MyFunction(expression)) { ... } #endif that someone else posted.

FryGuy
I'll give this a try as well
valerio
+1 Definitely the way I would go. Prevents Macro hell and will result in the same optimizations on most modern compilers.
0xC0DEFACE
+3  A: 

I generally try to avoid too much use of conditional compilation when possible.

For one, it's usually ugly and less readable.

But even more significantly, when projects use conditional compilation to turn debugging code on & off I have sometimes run into problems that the debugging code gets stale when it's disabled. Then when I want to actually use it debugging code, I turn it on and... Things. Don't. Build. Anymore.

The debug code may reference variables or functions that no longer exist, or things around the latent debugging code have otherwise changed enough that's it's just not syntactically valid anymore.

It can be really irritating.

So I've personally taken to avoiding conditional compilation to enable/disable debugging code in favor of using an enumeration or macro (that is still conditionally compiled) to use as the condition in an if statement. When compiled as an if (0) no runtime code gets generated - exactly as desired. But, the code is still compiled and syntax checked, so it's always at least syntactically correct.

#if NDEBUG  // using the same standard macro that `assert()` uses
            //  use your own if NDEBUG doesn't make sense
enum {
    DebugOn = 0
}
#else
enum {
    DebugOn = 1
}
#endif


// ... elsewhere

if (DebugOn) {
    // this always gets compiled, but if it's a release build
    //  the compiler will not emit anything...
}

As FryGuy mentioned, you can easily combine this with calling your MyFunction() if you like - in a release build, the function will not be called due to short-circuiting, which is the behavior you specified:

if (DebugOn && MyFunction( expression)) {
    // this always gets compiled, but if it's a release build
    //  the compiler will not emit anything...
}

But personally, I'd probably use

if (DebugOn) {
    if (MyFunction( expression)) {
        // ... 
    }
}

Which I think helps call out a little more clearly (just a little) that this is a debug-only block.

This has the advantages of always being compiled and having no flow control hidden behind macros (which several other answers have mentioned as an evil).

Michael Burr