C++57个入门知识点_05_ 内联函数(inline、函数体较小时使用、类似宏定义将函数二进制代码写入调用位置、对编译器的建议、debug版时编译器不听、内联函数必须写在头文件、跟qt匿名函数相似)

函数是有一段代码要经常的被调用,因此我们将其封装起来,变成代码块,代码块可以在程序的任何地方使用。那什么是内联函数呢?怎么使用?有什么性质?本篇将会进行介绍:

  • 为什么用内联函数:在函数体比较小时,程序运行时多次调用某函数的开销可能要大于函数本身。
  • 内联函数的本质:相当于将函数体代码带入调用位置,而不用跳转。宏也可以实现类似的功能,但是存在缺陷

内联函数的性质:

  • 内联函数是对编译器的建议,编译器可以听或不听的,将函数编译成内联或者非内联都是有可能。一般都会听,只有在函数体比较复杂的时候就不会编译为内联函数,当做普通函数。
  • 当代码为debug版时,编译器也是不会听的,因为程序在调试的时候需要知道函数体在哪一行进行跟踪。
  • 内联函数要在工程的很多地方都会调用,因此必须将内联函数写在头文件中。

1. 普通函数的调用过程

程序运行到函数时会跳转到函数体,并将实参传递到函数体,运行完成后跳出程序块并返回值给程序运行处。
下面代码会进入函数体getMax(int a, int b)3次:

#include <iostream>
int  getMax(int a, int b) {
	return  a > b ? a : b;//三目运算符
}

int main(int nArgc, char* pArgv[])
{
	int n1=getMax(1, 2);
	int n2=getMax(2, 3);
	int n3=getMax(2, 4);
	return 0;
}

上述代码的函数体很小,导致程序运行时多次调用某函数的开销要大于函数本身。形象化的比喻:对于喝水这件事情,可以去小卖部买水,但来回路上花费的功夫要大于你买水的动作,但是如果你家里本身就有水,那就不用花费时间去买水了

2. 宏定义实现内联


为了实现不用去小卖部就可以喝到水,可以使用宏的方式来定义:

#include <iostream>

#define GETMAX(a,b) ((a)>(b)? (a):(b))

int main(int nArgc, char* pArgv[])
{
	int n1= GETMAX(1, 2);
	int n2= GETMAX(2, 3);
	int n3= GETMAX(2, 4);
	return 0;
}

使用宏,编译器会将宏的代码写入main函数中的对应位置,上述的代码就会等价为:int n1= ((1)>(2)? (1):(2));

2.1 宏定义实现内联缺点


但是 宏除了有不进行类型检查的缺点,还会有可能造成预期结果与实际存在差异的情况,有以下代码:

#include <iostream>

#define GETMAX(a,b) ((a)>(b)? (a):(b))

int main(int nArgc, char* pArgv[])
{
	int n = 11;
	int n1= GETMAX(n++, 2);
	return 0;
}

F10单步运行结果:
在这里插入图片描述
在此过程中,n的值连续+1两次变为13,而不是预期的12,这是因为int n1= GETMAX(n++, 2);经过替换之后实际为int n1= ((n++)>(2)? (n++):(2));函数每执行完一次括号内内容就会+1一次,因此最终就会+1两次,而正常的函数调用就不会出现这种问题。但是调用函数又会有进出函数开销比较大的问题。

3. 内联函数使用及性质


C++中为了解决上面的问题,提出了内联函数,只需在函数前加 inline,这样就可以实现在函数调用的位置,编译就会像宏一样将函数的二进制代码放到了调用的位置。

3.1 内联函数是对编译器的建议


内联函数是对编译器的建议,编译器可以听或不听的,将函数编译成内联或者非内联都是有可能。一般都会听,只有在函数体比较复杂的时候就不会编译为内联函数,当做普通函数。

3.2 Debug版本没有Inline

还有一种情况是当代码为debug版时,编译器也是不会听的,因为程序在调试的时候需要知道函数体在哪一行进行跟踪。
在这里插入图片描述
Debug版本下进行函数调用反汇编的过程如下:可以看到虽然我们已经将函数体定义为内联,但进行的还是普通的函数调用。
(1)单步调试运行至函数被调用处
在这里插入图片描述
(2)打开反汇编窗口
在这里插入图片描述
(3)在反汇编窗口进行F10运行至下图红框处
在这里插入图片描述
(4)运行至红框后,F11运行进去
在这里插入图片描述
F10
在这里插入图片描述
(5)跳转至函数体
在这里插入图片描述

3.3 内联函数必须写在头文件

内联函数要在工程的很多地方都会调用,因此必须将内联函数写在头文件中。

inline.h

#pragma once
#include <iostream>
inline int  getMax(int a, int b) {
	return  a > b ? a : b;//三目运算符
}
#include <iostream>
#include "inline.h"

int main(int nArgc, char* pArgv[])
{
	int n = 11;
	int n1= getMax(n++, 2); 
	return 0;
}

使用内联函数也可以避免函数体重复调用的问题(int fool()在test.h中,在同一个工程中test1.cpp中包含test.h,test2.cpp中包含test.h,程序在链接的时候就会发现函数体int fool()被调用2次报错),因为其是将函数直接替换为函数体运行

4. 学习视频地址:C++57个入门知识点_05_ 内联函数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十月旧城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值