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