tags:

views:

130

answers:

4

If I write a function like this:

void doMaybeNothing()
{ 
#ifndef IM_LAZY
   doSomething();
#endif
}

Are modern compilers smart enough to detect a no-op function and optimize so that there are no cycles wasted? Or is there always a small performance impact?

+5  A: 

Assuming the body of the function is available at compile-time or link-time (i.e., it's not in a dynamically linked library), most modern compilers should get rid of calls to functions that do nothing (if optimizations are enabled, of course).

Effectively, this is just a form of inline expansion, which allows the body of a function to be expanded anywhere it is called, so long as the results are the same. If the function does nothing, then it will simply expand to nothing wherever it is inlined.

James McNellis
Glad you talked about link-time. Too many people assume there aren't any optimization performed once the compiler is done.
Matthieu M.
+5  A: 

Simple functions like this will be inlined and removed.

For gcc, with an input like

#include <stdio.h>

void no_op () {}

int main () {
    no_op();
    no_op();
    no_op();
    no_op();
    no_op();
    no_op();
    no_op();
    no_op();
    no_op();
    no_op();
    no_op();
    no_op();
    return 0;
}

The result (with -O1) is

    .section __TEXT,__text,regular
    .section __TEXT,__textcoal_nt,coalesced
    .section __TEXT,__const_coal,coalesced
    .section __TEXT,__picsymbolstub4,symbol_stubs,none,16
    .text
    .align 2
    .globl _no_op
_no_op:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    @ link register save eliminated.
    @ lr needed for prologue
    bx  lr
    .align 2
    .globl _main
_main:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    @ link register save eliminated.
    @ lr needed for prologue
    mov r0, #0
    bx  lr
    .subsections_via_symbols

Note that no call to no_op in main is generated.

KennyTM
ARM assembly? What kind of computer do you have?
kmm
@kmm: Just a Mac. With an ARM cross-compiler.
KennyTM
Are you saying gcc will inline them automatically, or do you still need to declare them as inline functions? Can I get away by leaving the function definition in a source file instead of the header?
0x80
Look at the example: `no_op` is not explictly defined `inline`, yet the assembly shows no calls to it. Hence we know it must have be inlined. However, this is possibly because the function was defined before its use in the same Translation Unit.
MSalters
+1  A: 

If the call to doMaybeNothing is in the same source file, then most modern compilers will optimize it completely away.

If the call is in a separate source file, and especially if it's in a different library, then you will often end up with the small overhead of the function call - but the function will immediately return.

One more thing: this sounds like premature optimization. Don't worry about things like this until you've profiled your program.

dmazzoni
Yes you're probably right about premature optimization, but its about an debug assert function which gets called very often including in process loops, so I was just wondering what would be a good approach.Inlining the thing with a preprocessor switch seems to be the right way.
0x80
A: 

Besides what the other answers have already mentioned, one other thing to consider is that the #ifndef is handled by the pre-processor, which just does text-replacement - not the compiler.
The compiler never sees anything except what the pre-processor spits out. So, depending on whether IM_LAZY is defined or not, the compiler will only see one of the following:

void MaybeDoNothing()
{
}

or

void MaybeDoNothing()
{
    doSomething();
}
tzaman
Thanks to everyone for your answers!
0x80