编译器是否会优化调用一次的函数

Will compiler optimize away called-once functions

提问人:acenturyandabit 提问时间:1/23/2023 最后编辑:cafce25acenturyandabit 更新时间:1/23/2023 访问量:52

问:

我一直在读 Robert C Martin 的《Clean Code》,其中一条建议是使用更多但更小的函数;即代替

int main(){

    // do one thing
    // ... 10 lines of code

    // do another thing
    // ... another 10 lines of code

    // one last thing
    // ... another 10 lines

    return 0;
}

你应该

int main(){
    doOneThing();
    doAnotherThing();
    oneLastThing();
}

void doOneThing(){
    ... 10 lines of code
}

// ... you get the idea

但是,根据我对低级语言的理解,我知道当调用函数时,变量被推送到堆栈上,堆栈指针递增,等等,而对于连续代码,则不需要这样做。

另一方面,编译器优化可以做一些很酷的事情,比如内联类方法。假设只调用一次,编译器是否可以调用此代码,推断出代码可以展开到,并完全消除函数调用和相关的运行时开销?doOneThingmain()

编译 与语言无关

评论

0赞 463035818_is_not_an_ai 1/23/2023
编译器可以并且执行内联函数,当他们看到性能提升时。调用函数是有成本的,但远少于 10 行。当函数为 0 或 1 行时,您可能会开始担心
1赞 463035818_is_not_an_ai 1/23/2023
当你尝试时,你发现了什么?
0赞 463035818_is_not_an_ai 1/23/2023
请选择一种语言
2赞 463035818_is_not_an_ai 1/23/2023
我错过了重新标记:/。恕我直言,这个问题与语言无关。内联、编译器优化的可能性、重构对运行时效率的影响等,很大程度上取决于所使用的语言。
1赞 Richard Critten 1/23/2023
[语言不可知论]使问题无法回答,因为“......编译器会优化吗...“取决于语言/编译器。

答:

1赞 463035818_is_not_an_ai 1/23/2023 #1

这个问题的先前版本是关于C++或C的。我相信它需要一种语言的上下文才能以有意义的方式讨论这个话题,所以我选择继续使用 C++。

C++并不是真正的“低级”。您编写的代码不是 CPU 的指令。在代码和运行时实际发生的情况之间,有一个最复杂的软件部分:编译器。当你打开优化时,你的编译器将分析你的代码,并尝试生成最有效的可执行文件,在运行时的行为就像你的代码在字面上一样(即没有优化)。

这是由所谓的“假设”规则支配的。调用函数不是可观察的行为。如果函数很小,编译器将对函数的调用内联。

另一方面,调用函数当然是有代价的,但这个代价相对较小。当函数非常小时,例如只有 1 或 2 行,并且(这很重要!)由于某种原因编译器无法内联调用时,您需要开始担心这种开销。例如,这可能是由于函数是虚拟的。

你问编译器是否可以优化它,所以我只选一个例子。Gcc with 将为以下代码生成以下输出:-O3

int foo() { return 42;}
int bar() { return 0;}
int moo() { return 1;}


int main() {
    return foo() + bar() + moo();
}

输出

foo():
        mov     eax, 42
        ret
bar():
        xor     eax, eax
        ret
moo():
        mov     eax, 1
        ret
main:
        mov     eax, 43
        ret

您可以看到 hat 没有被调用任何函数。编译器检查表达式并发现它始终等于 。无需调用任何函数即可返回 。mainfoo() + bar() + moo()4343

这是一个愚蠢的例子,尽管对于一般情况,如果你确实想看看编译器做了什么,你需要做同样的事情:查看编译器的输出。

为此,您需要先编写代码。首先推测哪种代码效率更高或效率更低是没有用的。您首先需要编写代码。而且因为无论如何你都需要这样做,所以你可以编写干净、简单、人类可理解的代码。这是你的编译器最能理解的代码,也知道如何优化,因为这也是其他程序员写的。