重识C/C++内联函数

内联函数是编译器在编译阶段做的优化,它的目的是减少函数的调用时间从而加快函数的运行,代价是代码量会增加,典型的空间换时间的优化。

什么是减少函数调用时间?

我们都知道传统调用函数的时候会把参数压入栈中,然后调用call指令进行跳转。函数执行的时候还要把参数从栈中取出,函数返回的时候还要把返回值放入寄存器,然后调用ret指令返回。如果对于一个复杂的函数这些开销不算什么,但是对于一个简单的函数比如向量的加法,这部分的开销相对来说就不小了。所以我们看DX的数学库全部采用内联函数来编写。内联函数会在编译器把函数的内容展开到调用的地方,简单的说就是把这部分的汇编代码插入到调用的地方,这样就不需要传递参数,进行函数跳转了。看上去和宏的使用方式很类似,但是它们还是有很大区别的,后面再讲。

要想定义一个内联函数只要在函数定义的时候加上inline关键字,比如

inline int add(int a, b)

{

     return a + b;

}

在调用内联函数的时候一定要有函数的定义,因为没有定义,编译器就不知道怎么展开函数了。

内联函数是编译器的优化,所以编译器会进行判断这个函数到底需不需内联,也就是说我们使用了inline关键字,编译器也不一定会把它当成内联函数,比如一个函数内有循环,递归,那么编译器就认为函数比较复杂,不需要做内联优化。放一段代码看看编译器是否会自动选择内联。

inline int add1(int a, int b)
{
	a++;
	b++;
	return a + b * b + a * a;
}

inline const int add2(int a, int b)
{
	float c = 0;
	for (int i = 0; i < 1000000000; i++)
	{
		float c = a + b;
		if (i > 1)
		{
			c += a;
		}
		else
		{
			float d = a + b;
			c += d;
		}
	}


	return c;
}

void main()
{
	add1(1,1);
	add2(2,2);
}

函数add1被当作内联函数处理了,函数add2没有被内联。如何查看是否内联成功了呢?通过反编译我们看一下汇编代码,如果内联成功,函数调用的时候不会有push和call操作,内联失败会进行push和call操作。

	add1(1,1);
00451808  mov         dword ptr [ebp-14h],1  
0045180F  mov         dword ptr [ebp-8],1  
00451816  mov         eax,dword ptr [ebp-8]  
00451819  add         eax,1  
0045181C  mov         dword ptr [ebp-8],eax  
0045181F  mov         ecx,dword ptr [ebp-14h]  
00451822  add         ecx,1  
00451825  mov         dword ptr [ebp-14h],ecx  
	add2(2,2);
00451828  push        2  
0045182A  push        2  
0045182C  call        add2 (0451055h)  
00451831  add         esp,8

在工程选项中可以设置设否启用内联优化。如果关闭内联优化,即使符合内联条件,编译器也不会进行内联处理。

内联函数和宏的区别

内联函数是发生在编译器,所以它可以进行函数参数的检查,如果参数有问题,会在编译器报错。

但是宏是发生在预编译阶段,它只是简单的字符串替换,无法进行参数检查。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值