#if 0 as a define

送分小仙女□ 提交于 2019-12-08 15:11:48

问题


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

回答1:


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



回答2:


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



回答3:


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.




回答4:


Why can't you use the following?

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



回答5:


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




回答6:


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


来源:https://stackoverflow.com/questions/2232737/if-0-as-a-define

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!