函数指针与指针函数的区别_函数指针调用与函数调用开销对比

问题背景:如题这个问题涉及到一个技术方案的选择,我们纠结于选择函数指针方案还是选择函数调用方案,为了支撑架构选择,做了一些试验。

理论分析:直观上看应该是函数调用开销更小。函数指针调用方案中需要先访问数据区,再访问函数,增加指令开销,同时,数据取值与函数指令加载必须串行执行,影响CPU流水性能;函数调用方案可以做内联优化。

首先,为了防止gcc进行内联优化,设计func.c供主程序进行跨文件访问,func.c如下:

int a = 1;

void func0()
{
	a++;
}
void func1()
{
	a++;
}
void func2()
{
	a++;
}
...
void func9()
{
	a++;
}

func.h为func对外提供的接口,func.h如下:

void func0();
void func1();
void func2();
...
void func9();

构造调用函数,直接进行文件调用的代码hello.c如下:

#include <stdio.h>
#include <time.h>
#include "func.h"

#define N 100000000

int main()
{
	clock_t start, end;
	start = clock();
	for(int i = 0; i < N; i++)
	{
		func0();
		func1();
		func2();
		func3();
		func4();
		func5();
		func6();
		func7();
		func8();
		func9();
	}
        end = clock();
        printf("%ld", end - start);
}

与之对比的用函数指针进行调用的代码hellocompare.c如下:

#include <stdio.h>
#include <time.h>
#include "func.h"

#define N 100000000
typedef void (*ffunc)();

int main()
{
	ffunc fffunc[10] = {func0, func1, func2, func3, func4, func5, func6, func7, func8, func9};
	clock_t start, end;
	start = clock();
	for(int i = 0; i < N; i++)
	{
		fffunc[0]();
		fffunc[1]();
		fffunc[2]();
		fffunc[3]();
		fffunc[4]();
		fffunc[5]();
		fffunc[6]();
		fffunc[7]();
		fffunc[8]();
		fffunc[9]();
	}
        end = clock();
        printf("%ld", end - start);
}

编译:

gcc -O0 -o a0 hello.c func.c func.h

gcc -O0 -o b0 hellocompare.c func.c func.h

类似地,O1 O2 O3优化命名为a1/b1 a2/b2 a3/b3,运行5次取平均,得到下表:

79eb909c91bf165fc86603780336f1c9.png

忽略掉1%以下的的情况,我们可以认为O1 O2 O3优化下的两种方式没有区别。在O0下,也就是说,不带任何优化,函数指针调用方式会损失6%的性能,证实了本文开头的分析。

这个小实验到这里还不算完,有两个问题:

  1. O1究竟做了什么,让两种方式性能没差别;
  2. 为什么优化等级高的程序,在这个场景下反而性能会变差。

问题1:

通过gcc -O1 -S hello.c func.c func.h,能看到生成的汇编,发现两种方式的汇编代码一模一样。O0下的直接调用的汇编代码:

	movl	$0, %eax	#,
	call	func0@PLT	#

函数指针调用汇编代码:

	movq	-96(%rbp), %rdx	# fffunc, _1
	movl	$0, %eax	#,
	call	*%rdx	# _1

果然,多了一行额外的指令。

问题2:

老夫愚钝,汇编语言已经还给了大学老师,短时间内无望搞清楚了。

综上,O0下,函数指针调用有6%损失,但O0以上与直接调用的性能没有差别。所以在O0以上,我们应只考虑内联优化带来的巨大收益。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值