我在C语言中读到了函数指针,每个人都说这会使我的程序运行缓慢。是真的吗?
我写了一个程序来检查它。我在两个案例中都得到了相同的结果。(测量时间。)
那么,使用函数指针是不是很糟糕呢?提前谢谢。
对一些人的回应。我说的是“慢跑”,因为我在循环中进行了比较。如下所示:
int end = 1000;
int i = 0;
while (i < end) {
fp = func;
fp ();
}当你执行这个的时候,如果我执行这个,我会得到相同的时间。
while (i < end) {
func ();
}所以我认为函数指针没有时间差,它不会像许多人说的那样使程序运行缓慢。
发布于 2010-03-14 01:53:46
您看,从性能的角度来看,在一些实际很重要的情况下,比如在一个周期中重复多次调用函数,性能可能根本不会有什么不同。
这对人们来说可能听起来很奇怪,他们习惯于将C代码看作是由抽象的C机器执行的东西,其“机器语言”紧密地反映了C语言本身。在这样的上下文中,“默认情况下”对函数的间接调用确实比直接调用慢,因为它正式地涉及到额外的内存访问,以便确定调用的目标。
然而,在现实生活中,代码是由真实的机器执行的,并由优化编译器编译,该编译器对底层机器架构有很好的了解,这有助于它为特定机器生成最优的代码。在许多平台上,从循环执行函数调用的最有效方法实际上会导致直接调用和间接调用的代码相同,从而导致两者的性能相同。
例如,考虑x86平台。如果我们“从字面上”将直接和间接调用转换成机器代码,我们可能会得到如下所示的结果
// Direct call
do-it-many-times
call 0x12345678
// Indirect call
do-it-many-times
call dword ptr [0x67890ABC]前者在机器指令中使用立即操作数,并且通常比后者更快,后者必须从一些独立的内存位置读取数据。
在这一点上,让我们记住,x86架构实际上还有一种向call指令提供操作数的方法。它在寄存器中提供目标地址。关于这种格式的一个非常重要的事情是,它通常比上面两种格式都快。这对我们意味着什么?这意味着一个好的优化编译器必须并将利用这一事实。为了实现上述循环,编译器在这两种情况下都会尝试通过寄存器进行调用。如果成功,最终的代码可能如下所示
// Direct call
mov eax, 0x12345678
do-it-many-times
call eax
// Indirect call
mov eax, dword ptr [0x67890ABC]
do-it-many-times
call eax请注意,现在重要的部分-循环体中的实际调用-在这两种情况下是完全相同的。不用说,性能几乎是一样的。
有人甚至可能会说,无论听起来多么奇怪,在这个平台上,只要间接调用的操作数是在寄存器中提供的(而不是存储在内存中),直接调用(带有call中的立即操作数的调用)就比间接调用慢。
当然,在一般情况下,整个事情并不容易。编译器必须处理寄存器的有限可用性,别名问题等。但像你的例子(甚至在更复杂的情况下)这样的简单情况下,上述优化将由一个好的编译器执行,并将完全消除循环直接调用和循环间接调用之间的任何性能差异。当调用虚拟函数时,这种优化在C++中工作得特别好,因为在典型的实现中,涉及的指针完全由编译器控制,使其完全了解别名图片和其他相关内容。
当然,总是有一个问题是,你的编译器是否足够智能来优化这样的东西……
发布于 2010-03-13 21:50:40
我认为当人们这样说的时候,他们指的是使用函数指针可能会阻止编译器优化(内联)和处理器优化(分支预测)。然而,如果函数指针是完成你想要做的事情的一种有效方法,那么任何其他的方法都有同样的缺点。
除非您的函数指针在性能关键型应用程序或速度非常慢的嵌入式系统中的紧密循环中使用,否则差异可能是微不足道的。
发布于 2010-03-14 01:51:10
和每个人都说这会使我的程序运行缓慢。是真的吗?
这种说法很可能是错误的。例如,如果使用函数指针的替代方法类似于
if (condition1) {
func1();
} else if (condition2)
func2();
} else if (condition3)
func3();
} else {
func4();
}这很可能比仅仅使用单个函数指针要慢得多。虽然通过指针调用函数确实有一些(通常可以忽略的)开销,但与比较相关的通常不是直接函数调用与通过指针调用的差异。
其次,在没有任何测量的情况下,永远不要优化性能。要知道瓶颈在哪里是非常困难的(请参阅 it ),有时这可能非常不直观(例如,linux内核开发人员已经开始从函数中删除inline关键字,因为它实际上会影响性能)。
https://stackoverflow.com/questions/2438539
复制相似问题