Does Function pointer make the program slow?

前端 未结 8 2577
你的背包
你的背包 2020-11-29 21:10

I read about function pointers in C. And everyone said that will make my program run slow. Is it true?

I made a program to check it. And I got the same results on bo

8条回答
  •  無奈伤痛
    2020-11-29 21:43

    Possibly.

    The answer depends on what the function pointer is being used for and hence what the alternatives are. Comparing function pointer calls to direct function calls is misleading if a function pointer is being used to implement a choice that's part of our program logic and which can't simply be removed. I'll go ahead and nonetheless show that comparison and come back to this thought afterwards.

    Function pointer calls have the most opportunity to degrade performance compared to direct function calls when they inhibit inlining. Because inlining is a gateway optimization, we can craft wildly pathological cases where function pointers are made arbitrarily slower than the equivalent direct function call:

    void foo(int* x) {
        *x = 0;
    }
    
    void (*foo_ptr)(int*) = foo;
    
    int call_foo(int *p, int size) {
        int r = 0;
        for (int i = 0; i != size; ++i)
            r += p[i];
        foo(&r);
        return r;
    }
    
    int call_foo_ptr(int *p, int size) {
        int r = 0;
        for (int i = 0; i != size; ++i)
            r += p[i];
        foo_ptr(&r);
        return r;
    }
    

    Code generated for call_foo():

    call_foo(int*, int):
      xor eax, eax
      ret
    

    Nice. foo() has not only been inlined, but doing so has allowed the compiler to eliminate the entire preceding loop! The generated code simply zeroes out the return register by XORing the register with itself and then returns. On the other hand, compilers will have to generate code for the loop in call_foo_ptr() (100+ lines with gcc 7.3) and most of that code effectively does nothing (so long as foo_ptr still points to foo()). (In more typical scenarios, you can expect that inlining a small function into a hot inner loop might reduce execution time by up to about an order of magnitude.)

    So in a worst case scenario, a function pointer call is arbitrarily slower than a direct function call, but this is misleading. It turns out that if foo_ptr had been const, then call_foo() and call_foo_ptr() would have generated the same code. However, this would require us to give up the opportunity for indirection provided by foo_ptr. Is it "fair" for foo_ptr to be const? If we're interested in the indirection provided by foo_ptr, then no, but if that's the case, then a direct function call is not a valid option either.

    If a function pointer is being used to provide useful indirection, then we can move the indirection around or in some cases swap out function pointers for conditionals or even macros, but we can't simply remove it. If we've decided that function pointers are a good approach but performance is a concern, then we typically want to pull indirection up the call stack so that we pay the cost of indirection in an outer loop. For example, in the common case where a function takes a callback and calls it in a loop, we might try moving the innermost loop into the callback (and changing the responsibility of each callback invocation accordingly).

提交回复
热议问题