开发者

#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


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


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


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.


Why can't you use the following?

#ifdef DEBUG
code for debug mode
#else
code for release mode
#endif


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).


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
  })
)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜