编译器是否会优化通过指针调用的微不足道的函数?

17

假设我有一个接受函数指针的函数:

int funct(double (*f)(double));

我会将其传递给一个实际上不做任何事情的函数:

double g(double a) { return 1.0;}
//...
funct(g);

编译器会优化对 g 的调用吗?还是这仍然会有开销?如果确实有开销,那么这个开销有多大?开销足够大到值得重载函数来接收函数指针和常量值吗?

3个回答

17
较新版本的GCC(4.4及之后)可以使用选项-findirect-inlining来内联和优化已知函数指针。这仅在GCC也知道使用该指针的所有代码时才有效。
例如,C库函数qsort将无法从此优化中受益。qsort的编译机器码在库中,它期望一个函数指针,编译器无法更改这一点。
然而,如果您有自己的qsort实现,并将其放在头文件中或使用非常新的GCC链接时间优化功能,则GCC将能够将您的调用代码、指向的函数和您的qsort源代码一起编译,针对您的数据类型和比较函数进行优化。
现在,仅在函数调用开销远大于函数本身时,才真正需要这样做。对于一个几乎什么都不做的函数的示例,使用函数指针是严重的开销。在我的qsort比较示例中,函数指针调用也相当昂贵。但在某些其他应用程序中,如Windows事件调度,这几乎无关紧要。
由于您正在使用C ++,因此您应该学习模板。模板函数可以接受所谓的“函数对象”,它只是实现了operator()的对象,并且可以接受函数指针。传递函数对象将允许C ++编译器内联和优化几乎所有相关代码。

模板是另一种管理这个的方式,我仍然可能会使用它们,但是我不太理解它们(我还在学习),所以函数指针将是简单的解决方法。 - Andrew Spott
GCC将会知道使用指针的全部代码,然而funct可能会成为另一个文件中一个类的一部分(并且该类中许多不同的方法将使用funct)。GCC能够进行优化吗?不幸的是,由于性能方面对此代码足够敏感,我必须思考它(g可能会被调用超过几十万次)。 - Andrew Spott

2
任何现代编译器都可以(并且将会)在编译时优化掉通过函数指针调用的情况,即使该指针指向的位置在编译时已知。
在你所提供的示例中,一般情况下不能在调用时预测指针的值,因为它作为函数 funct 的参数从外部传入。如果函数 funct 本身足够小以便内联,则运行时参数将被消除,整个 funct 代码将在 funct 的调用者上下文中“溶解”。如果在该调用者上下文中已知指针的值,则编译器可以轻松地消除对指针的调用。
最后,如果 funct 函数相对较重(即无法内联),则您应该预计编译器将从 funct 中通过指针生成普通的运行时调用。在这种情况下,消除调用的潜力也存在,因为编译器可以为每个编译时值 g 生成一个单独的 funct 版本。例如,如果您有:
int funct(int x1, int x2, int x3, double (*f)(double));

这个函数只接受两个参数 f

funct(rand(), rand(), rand(), g1);
...
funct(rand(), rand(), rand(), g2);

然后编译器可以将其“简化”为两个函数。
int funct_g1(int x1, int x2, int x3);
int funct_g2(int x1, int x2, int x3);

没有函数指针参数,直接调用 g1g2 的情况下进行优化。(当然,这种优化与函数指针无关,可以应用于任何仅使用一小组固定参数的函数参数。实际上,这类似于 C++ 模板。)但我不知道有哪些编译器会执行这样的操作。


1

编译器可能不会对其进行优化,因为函数funct可以接收指向不同函数的指针,而不仅仅是g,它们也不必来自同一编译单元(因此编译器不能假设它知道所有可能的调用)。

您需要对代码进行基准测试,以确定您所说的优化是否必要,如果确实需要-就去做。但是,除非funct经常调用g,否则我不认为这很重要。


编译器可以通过指针优化函数调用,即使有多个调用,即使函数在不同的翻译单元中。这被称为完全程序优化,是在链接时完成的。 - Gene Bushuyev
编译器和链接器之间的区别并不像过去那样清晰。现在,在链接时、运行时进行优化和代码生成。 - Gene Bushuyev
2
有时候,gcc会在这种情况下简单地生成两个函数:一个用于已知函数指针的情况,另一个用于一般情况。采用这种方法,链接器不需要做任何特殊处理。 - Sven Marnach
“funct” 可能会调用 “g” 几十万到几百万次……或者更多。 :) - Andrew Spott
@spot - 那我建议不要依赖于编译器优化。 - littleadv
@spot - 这是每秒还是每小时几百万次? :-) - Bo Persson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接