我看到了一些像这样的代码
int *func2(int *var) {
//Do some actual work
return var;
}
int *func1(int *var) {
return func2(var);
}
int main() {
int var;
var = func1(&var);
return 0;
}
这对我来说似乎是一种令人难以置信的浪费,但我认为中间功能可能以前有两个可以调用的功能,或者将来有一些扩展计划。我只是想知道像gcc这样的编译器是否可以检测到这种情况并消除实际程序中的无用功能,或者这种事情是否在运行时浪费了CPU周期?
答案 0 :(得分:12)
不要过早优化。专注于编写可读代码。即使没有优化,额外的函数调用可能对性能的影响很小。编译器可以选择内联它。
如果您以后遇到性能问题,可以进行测试和配置以查找瓶颈。
答案 1 :(得分:4)
在大多数情况下,如果您将编译器优化调高到足够高,那么这些简单的函数将是inlined。因此没有开销。
所以问题的答案是:是的,编译器通常足够聪明,可以消除呼叫。
所以除非你需要,否则不要担心。
您还可以使用inline
关键字使其更明确:(尽管编译器仍然可以忽略它)
inline int *func1(int *var) {
return func2(var);
}
答案 2 :(得分:1)
超快的回答:是的,也许。
快速回答:是的,但通常不够,你应该关心,有时根本不关心。
完整的答案:如果函数都在同一个翻译单元中并且编译器没有吮吸,那么额外的函数调用层将被优化掉,并且会有零影响在表现上。否则,如果您正在进行外部函数调用,则需要较小但非零的性能成本。大多数时候它并不重要,但对于每个周期都很重要的超短函数,它可能会使你的程序慢两倍或更糟。一些最坏情况的例子:
getc
这样的函数只是从缓冲区中提取下一个字节,使位置前进,然后返回(在缓冲区非空的常见情况下)。lock(); a++; unlock();
)保留锁定,那么即使锁定所持有的少量额外时间也会对争用性能产生严重影响(如果锁定具有高度争用性)。 最后,你应该做什么回答:尽可能以最自然的方式编写代码,直到测试/测量显示出存在性能问题。只有这样才能考虑为了性能而丑化你的代码。
答案 3 :(得分:0)
这取决于编译器和运行时环境。如果方法调用在堆栈上,则递增堆栈会有一些额外的开销。但在这种情况下,一切都是通过指针,所以这可能是一个尾调用,可能会内联。内联/尾调用将导致函数操作类似于跳转而不是堆栈递增;这意味着它在运行时类似于循环或goto。