在优化的代码中是否调用了空函数?

Is an empty function called at all in optimised code?

提问人:Pietro 提问时间:7/1/2011 最后编辑:cigienPietro 更新时间:8/4/2021 访问量:7625

问:

如果未定义 TEST 宏,我想知道这两段代码是否存在性能差异:

void Func1(int a) {
   // ...
}

#ifdef TEST
Func1(123);
#endif

和:

void Func2(int a) {
#ifdef TEST
    // ...
#endif
}

Func2(123);

如果未定义,将成为一个编译器根本不应该调用的空函数,不是吗?TESTFunc2

C++ 优化 性能 运行时

评论

12赞 R. Martinho Fernandes 7/1/2011
专业提示:查看编译器的程序集输出,然后自己看看。
5赞 Jack Kelly 7/1/2011
继 @Martinho 的评论之后:如果你正在使用,那么标志将指示编译器输出汇编程序,这样你就可以自己看到发生了什么。尝试使用不同的优化设置。gcc-S-O
1赞 Robin Hsu 12/15/2014
我不相信。在 C/C++ 中,首先编译程序,然后链接程序。这两个步骤基本上是独立的。此外,两个不同函数的编译也基本独立。因此,除了内联函数外,在编译时,当要编译函数调用时,它并不知道要调用的函数是一个空函数。它只是遵循调用约定(准备参数,如果有的话)来为函数调用生成中间代码。在链接步骤中,它实际上修改了中间代码以固定呼叫地址。
1赞 Steve Jessop 12/17/2014
@RobinHsu:当你说“内联函数除外”时,你应该说“内联函数除外”。使用现代优化编译器,您可以假设函数调用是否内联或多或少与函数是否被标记无关。inline
1赞 Robin Hsu 12/17/2014
@Steve Jessop:嗯,对于内联函数,我实际上指的是那些写在头文件中的函数。因为在头文件中,它在使用之前是完全包含的。因此,编译器可能在到达调用空函数的行之前就知道它是空的。否则,优化只能在链接时间内进行。这意味着在编译时,它必须生成两个代码选择,一个用于普通代码,另一个用于选择退出代码。然后,将选择委托给链接器。是的,我承认以这种方式,编译器/链接器可以选择退出空函数。

答:

2赞 DevSolar 7/1/2011 #1

优化通常是特定于编译器的。AFAIK语言标准没有对什么应该优化,什么不应该优化做出任何声明。(虽然我承认我没有读过语言规范本身。

每个编译器都有自己的一组选项,通过这些选项可以启用/禁用特定的优化步骤。

所以答案是明确的“视情况而定”,以及“你必须检查自己才能确定”。

(但是,如果一个中规中矩的优化器会让这样的结构未得到优化,我会感到非常惊讶。

评论

0赞 R. Martinho Fernandes 7/1/2011
该标准确实告诉了不应该优化的事情(比如,对可变变量的访问)。有时,它还会告诉可以进行哪些优化(例如复制省略)。
0赞 DevSolar 7/1/2011
@Martinho Fernandes:在谈论优化时,我从来不会想到,因为在我看来,它们在某种程度上是两回事。当然,你是对的。但是在这个问题的层面上,C99没有做任何声明,如果C++做了,我会感到惊讶。volatile
0赞 MSalters 7/3/2011
@DevSolar:优化的目标是在保持相同可观察行为的同时转换代码。 被明确定义为可观察的行为,因此它们密切相关。(其他可观察的行为是调用特定的库函数)。volatile
9赞 Steve Jessop 7/1/2011 #2

这几乎归结为该特定调用是否是内联的。如果是这样,那么优化编译器应该能够对空函数进行内联调用,就像根本不调用它一样。如果它未内联,则会调用并立即返回。Func2

只要函数定义在包含调用的 TU 中可用,就没有明显的理由不将其内联。Func2

这一切都依赖于字面意思这一事实,因此评估调用的论点没有副作用。即使函数调用不起作用,也必须计算参数,因此:123

int i = 0;

/* 'i' is incremented, even if the call is optimized out */
Func2(++i);

/* 'i' is not incremented when 'TEST' is undefined */
#ifdef TEST
Func1(++i);
#endif

评论

0赞 Matthieu M. 7/1/2011
别忘了链接时间优化:)
0赞 Steve Jessop 7/1/2011
@Matthieu:我没有忘记,我故意没有说当函数定义不在 TU 中时会发生什么;