3

I'm trying to removed unused code from my program - I can't delete the code for now, I just want to disable it for a start.

Let's say that I have the following code:

if (cond){
  doSomething()
}

and cond is always false so doSomething is never called.

I want to do something like:

#define REMOVE_UNUSED_CODE 0
if (cond && REMOVE_UNUSED_CODE){
  doSomething()
}

Now this is obvious to us (and hopefully for the compiler) that this code is unused.

Will the compiler remove all this if condition or it will leave it and never get in?

P.S.: I can't use #if 0 for this purpose

WedaPashi
  • 3,561
  • 26
  • 42
Shai Zarzewski
  • 1,638
  • 3
  • 19
  • 33
  • `cond` will get evaluated at runtime - how do you expect it to be known at compile time? – Sadique May 12 '15 at 10:37
  • @al-Acme I guess OP is asking about `REMOVE_UNUSED_CODE`. – Sourav Ghosh May 12 '15 at 10:39
  • I am not sure about the compiler standards, but compiler should be able to recognize the `REMOVE_UNUSED_CODE` and keep out the dead part, with proper optimization enabled. Not very sure, though. – Sourav Ghosh May 12 '15 at 10:40
  • 1
    Can't you just try it? Also no one can tell you what "the" compiler will do if you don't even tell use which compiler (and which optimization level) you're asking about. I'd be pretty confident that most compilers with optimizations enabled will be able to figure out that `x && false == false` - assuming that `cond` can be easily determined to have no side-effects. – sepp2k May 12 '15 at 10:44
  • The fact that this is apparently for a safety-critical system (mentioned below) is kinda important, and should be in the question - safe/reliable code isn't usually allowed to be optimized in the same ways as "regular" code, as higher-end compiler optimizations can *sometimes* introduce different logic from what was originally written (I don't think it changes the actual answer to this specific question - this is a very basic optimization, first-tier - but it's a very important thing to be aware of in general). – Alex Celeste May 12 '15 at 11:24
  • @Leushenko Compiler optimizations can only affect behavior if the code relies on undefined behavior, which safety-critical code should never ever do (in fact no code should). – sepp2k May 12 '15 at 12:15
  • I would rather write `if (REMOVE_UNUSED_CODE && cond)` because boolean operators in C are always evaluated in short-circuit, and this way you avoid the possible `cond` side effects. – rodrigo May 12 '15 at 12:26
  • @sepp2k that depends on the compiler, e.g. [`-ffast-math`](http://stackoverflow.com/questions/7420665/what-does-gccs-ffast-math-actually-do) breaks the standard. Undefined behaviour is a concept from the abstract language; optimizations exist entirely in the realm of implementation "extensions" by definition, so one should always check to see what transformations are documented. On a different level, unoptimized code provides less surface for possible compiler bugs to affect anything. – Alex Celeste May 12 '15 at 13:06

6 Answers6

3

GCC will explicitly remove conditional blocks that have a constant expression controlling them, and the GNU coding standards explicitly recommend that you take advantage of this, instead of using cruder methods such as relying on the preprocessor. Although using preprocessor #if may seem more efficient because it removes code at an earlier stage, in practice modern optimizers work best when you give them as much information as possible (and of course it makes your program cleaner and more consistent if you can avoid adding a phase-separation dependency at a point where it isn't necessary).

Decisions like this are very, very easy for a modern compiler to make - even the very simplistic TCC will perform some amount of dead-code elimination; powerful systems like LLVM and GCC will spot this, and also much more complex cases that you, as a human reader, might miss (by tracing the lifetime and modification of variables beyond simply looking at single points).

This is in addition to other advantages of full compilation, like the fact that your code within the if will be checked for errors (whereas #if is more useful for removing code that would be erroneous on your current system, like references to nonexistent platform functions).

Alex Celeste
  • 12,824
  • 10
  • 46
  • 89
2

Try

#ifndef REMOVE_UNUSED_CODE
if (cond) {
   doSomething();
}
#endif

Instead. Don't forget to do a

#define REMOVE_UNUSED_CODE

somewhere.

rost0031
  • 1,894
  • 12
  • 21
1

The answer depends on the implementation of the compiler. You should never depend on this.

Instead be explicit:

#define REMOVE_UNUSED_CODE 0
if (cond && REMOVE_UNUSED_CODE){
#ifndef REMOVE_UNUSED_CODE  
   doSomething()
#endif
}
  • 1
    I don't see how it would depend on the compiler. It would have to be a pretty daft compiler not to optimize away the unused code. I don't think such bad compilers exist on the market. – Lundin May 12 '15 at 10:52
  • 1
    I agree, I would assume the same. However to know for absolute sure, its safer to be explicit. If the result was going to be life or death, you wouldn't make that assumption. – Phil Williams May 12 '15 at 10:54
  • 1
    If the result was going to be life or death (safety-critical applications), there are numerous standards for such systems that explicitly ban constructs like this. In safety-critical systems you are not allowed to have any code which is never executed. – Lundin May 12 '15 at 10:58
  • that's the case here.. this is a safety-critical system, and i'm doing a coverage test to remove all unexecuted code. first step if to disable all this code and later re-run major tests to see that no performance issues found – Shai Zarzewski May 12 '15 at 11:07
  • If you want to know for sure, just look at the object code. Use the switch that comments the assembly with the c code. – Phil Williams May 12 '15 at 11:30
0

Looking at this snippet of your code

#define REMOVE_UNUSED_CODE 0

if(cond && REMOVE_UNUSED_CODE)
{
    doSomething();
}

REMOVE_UNUSED_CODE is replaced with 0 by preprocessor before compilation. So if(cond && 0) will always be evaluated as false and will never be executed. So you can say, irrespective of what cond is, it will always be false.

So I'd rather prefer it doing this way:

//#define REMOVE_UNUSED_CODE 0

#ifdef REMOVE_UNUSED_CODE
    if(cond)
    {
        doSomething();
    }
#endif
WedaPashi
  • 3,561
  • 26
  • 42
0

You should not do it that way:

Suppose you have a function bool f(void* input) with side effects.

Then with

if( f(pointer) && false ) { ... }

the body is not evaluated, but f should be.

In the case of

if( false && f(pointer) ) { ... }

f is not evaluated because of the short-cut rule of the &&operator.

If you use

#define REMOVE_UNUSED_CODE
#ifndef REMOVE_UNUSED_CODE
if( f(pointer) && false ) { }

#endif

the whole code is not even compiled in and will never be executed.

martin
  • 3,149
  • 1
  • 24
  • 35
0

Not a direct answer, but may be helpful. There are compiler-specific intrinsics to do code removal.

For MSVC, it is __assume(0)

For GCC/Clang, it is __builtin_unreachable().

Notice, however, that if you write something like:

if (cond){
  __builtin_unreachable();
  doSomething()
}

Your condition should never evaluate to true, otherwise behavior is undefined. Combining both && REMOVE_UNUSED_CODE and __builtin_unreachable() ensures that your code will be removed by the compiler.