您现在的位置是:首页 >其他 >【C++入门】你知道C++为什么会有内联函数吗?网站首页其他
【C++入门】你知道C++为什么会有内联函数吗?
?个人主页:@Weraphael
✍?作者简介:目前学习C++和算法
✈️专栏:C++航路
? 希望大家多多支持,咱一起进步!?
如果文章对你有帮助的话
欢迎 评论? 点赞?? 收藏 ? 加关注✨
前言
本章是补充C语言语法的不足,以及C++是如何对C语言设计不合理的地方进行优化的。
一、问题引入
我们每次去调用函数的时候,都会有消耗(建立栈帧等等)。假设我现在要调用100次Add
函数,那么就要建立100个栈帧
在C语言中,为了防止如此大的消耗,我们通常用宏函数来解决问题。宏函数的优势:不需要建立栈帧,提高调用效率。
这里就得提提宏函数书写的经典错误了 (面试常考!!!)
- 宏代码本身不是函数,它是一种替换,因此不需要类型
- 末尾不需要分号
- 括号问题
①有的人可能会这么写#define Add(x, y) x+y
,那么如果有人给出这么一串代码Add(1, 1) * 2
就会出现问题。原因是:宏替换后就会变成—>1 + 1 * 2
,而我们期望的是先算1 + 1
,然而宏替换后,根据运算符的优先级,它会先算1 * 2
②还有的人可能会这么写#define Add(x, y) (x+y)
,那么如果有人给出这么一串代码Add(a|b, a&b)
就会出现问题。原因是:宏替换后就会变成–>(a|b + a&b)
,所以说,它还是因为优先级的问题,我们期望是先计算出a|b
和a&b
,然而,根据运算符的优先级,它会先算b+a
宏既然有优点,那一定就会有缺点(复杂、不易调试、代码可读性差),那就是特别容易书写写错误。因此,Bjarne Stroustrup
大佬看不下去了,于是自创了一个新语法 — 内联函数
二、内联函数的概念
以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,能提升程序运行的效率。
所以,在【问题引入】中,用内联函数表示方法如下:
通过以上代码,我们可以看出内联函数的优点是(解决了宏的缺点):
①不需要建立栈帧
②不复杂、不容易出错、可读性好、容易调试
三、内联函数的特性
有的人说,既然内联函数这么好,那可不可以将所有的函数都内联函数来表示?答案是当然不行,会导致代码膨胀(下面第一点会解释)!内联函数值适用于短小其频繁调用的函数
-
inline
是一种以空间换时间的做法。假如有一个Func函数有50
行指令,假设某个项目要调用1w
次Func
函数,如果不使用内联函数,就会有1w+50
行指令;如果使用内联函数,在编译阶段,会用函数体替换函数调用,就会1w*50
行指令,这会导致最后可执行程序(安装包)变大,谁会希望一个程序的安装包大呢?这就是代码膨胀,因此不能让所有的函数变成内联函数 -
inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,最终是否会称为inline,编译器自己决定。
如果在函数前增加inline关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的调用。
VS编译器的查看方式:
- 在
release
模式下,查看编译器生成的汇编代码中是否存在call xxx
- 在
debug
模式下,inline
不起作用,否则不方便调试了,但是在release
下又不方便看反汇编,所以可以稍微更改VS的属性来查看,步骤如下:右击项目,点击属性
在属性页中点击C/C++,对常规进行更改如下:
然后再点击优化,更改操作如下:
最后点击应用即可,然后我们就可以进入调试(F10)反汇编查看(右击即可查看)了,下面就是内联函数的调用,只要我们没有观察到call xxx
就代表着是内联函数了
当然,我们可以增加代码行,即使是加了inline
,编译器也不会支持
- inline不建议声明和定义分离,
看似没错,其实程序最后会报错
这是因为:分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到
所以内联函数的定义和声明一定要在一起
四、面试题
宏的优缺点?
优点:
- 增强代码的复用性。
- 提高性能。
缺点:
- 不方便调试宏。(因为预编译阶段进行了替换)
- 导致代码可读性差,可维护性差,容易误用。
- 没有类型安全的检查 。
C++有哪些技术替代宏?
- 常量定义 换用const enum
- 短小函数定义 换用内联函数