在C中实现类似OO的代码封装和多态的常用方法是将不透明指针返回到包含一些函数指针的结构。这是一个非常频繁的模式,例如在Linux内核中。
使用函数指针而不是函数调用引入了一个开销,这个开销由于缓存而几乎可以忽略不计,正如其他问题中已经讨论过的那样。
然而,对于GCC(> 4.6)的新-fwhole-program和-flto优化选项,事情会发生变化。
#include <stdlib.h>
#include "libPointers.h"
void do_work(struct worker *wrk, const int i)
{
wrk->datum += i;
}
struct worker *libPointers_init(const int startDatum)
{
struct worker *wrk = malloc (sizeof (struct worker));
*wrk = (struct worker) {
.do_work = do_work,
.datum = startDatum
};
return wrk;
}
#ifndef __LIBPOINTERS_H__
#define __LIBPOINTERS_H__
struct worker {
int datum;
void (*do_work)(struct worker *, int i);
};
extern void do_work (struct worker *elab, const int i);
struct worker *libPointers_init(const int startDatum);
#endif //__LIBPOINTERS_H__
#include <stdio.h>
#include "libPointers.h"
int main (void)
{
unsigned long i;
struct worker *wrk;
wrk = libPointers_init(56);
for (i = 0; i < 1e10; i++) {
#ifdef USE_POINTERS
wrk->do_work(wrk,i);
#else
do_work(wrk,i);
#endif
}
printf ("%d\n", wrk->datum);
}
使用-O3进行编译,但没有-flto -fwhole-program标志,testPointers执行在我的机器上大约需要25秒,无论USE_POINTERS是否为#defined。
如果我打开 -flto -fwhole-program 标志,testPointers使用USE_POINTERS #defined大约需要25秒,但如果使用函数调用大约需要14秒。
这是完全预期的行为,因为我理解编译器将内联并优化循环中的函数。但是,我想知道是否有一种方法可以帮助编译器告诉它函数指针是不变的,因此也允许它优化这种情况。
对于那些使用cmake的人来说,这就是我编译它的方式
set (CMAKE_C_FLAGS "-O3 -fwhole-program -flto")
#set (CMAKE_C_FLAGS "-O3")
add_executable(testPointers
libPointers.c
testPointers.c
)
答案 0 :(得分:10)
编译器不能内联函数,除非它可以确定只调用该函数的一个可能版本。通过指针调用,这是非常明显的。编译器仍有可能弄明白,因为如果你遵循代码,指针只能有一个可能的值;但是这超出了我对编译器的期望。
答案 1 :(得分:0)
如果在循环中调用函数指针,则可以在函数指针内移动循环。