C++内联函数inline详解

目录

据说点赞的人今天会有好运哦~

什么是内联函数?

内联函数解决什么问题?

关于声明文件和定义文件分离?

第二种方式解决:static静态函数

第三种方式:内联函数inline

相关知识:

auto//自动推导类型

容器for



据说点赞的人今天会有好运哦~

什么是内联函数?

内联函数(inline加在返回值的前面)
理解内联函数,首先理解宏,什么是宏?宏本质上是一个替换:
#define  A  B  //把A换成B(A、B可以是表达式,也可以是某些值)
#define ADD(a , b)  ((a)+(b))//外面的括号是为了确保优先级,里面的括号是因为有可能a或者b是一个表达式
确保优先级不被改变
内联函数就是借用了宏的特点,就是-调用时展开


内联函数解决什么问题?


在C语言中,当一个函数多次调用的时候会建立多个栈帧,耗时耗力
所以,为了避免多次建立栈帧的消耗
祖师爷于是使用了内联函数
什么是内联函数呢?
就是-调用时展开
说白了,就是在调用这个函数的时候不去建立函数栈帧了
而是直接将函数在函数调用处给展开了(注意,展开就无法调试了)
所以叫做,inline,很形象
注意:函数展开,并不是说就是简单的把函数代码拷贝过来
而是在汇编阶段,按照一定的逻辑加载到汇编部分执行

那么,既然说,内联函数避免了建立函数栈帧,减少了函数栈帧的消耗
那么,我们是不是可以把所有的函数都写成inline函数?
这样是不是就可以避免了所有的函数栈帧的消耗,从而加快了效率?
非也非也!
下面设想一个场景:
有一个函数func,100行,需要执行1w次数
如果是inline函数,展开在汇编阶段,忽略其他,我们就认为是100行指令
那么,总的也就是100w行指令
那么,最后形成的out文件就会非常的大,同时,执行一百万个执行,你觉得效率会很快吗?
肯定不会快

那么,如果不是inline函数呢?
就是正常的建立函数栈帧,建立1w个函数栈帧
而在汇编阶段,100行的代码是已经加载好了的
后面每一次调用函数,就是call和jump两个指令,转到100行函数内部代码的地方进行执行
也就是说,是10100行代码
孰慢孰快一目了然
所以,而并不是说用了inline就一定快

总体来说,内联函数是一种以空间换时间的策略
但是,这个空间不是内存空间,而是编译完成的可执行程序
这个可执行程序会变大
如果是小程序,例如说就几行,那么可执行程序膨胀不会那么严重
所以,事实上,内联函数只是一个请求,编译器对内联函数并不是统统都会展开,展开与否要具体要看编译器,代码太多的函数就不会展开

同时,内联不建议声明和定义分离

关于声明文件和定义文件分离?


为什么声明文件和定义文件要声明定义分离,解决链接冲突:
假设没有声明定义分离,而是直接在头文件内定义函数,然后在定义文件顶部写一个头文件
这样,就会导致,编译链接的时候,在定义文件内,头文件展开,导致定义文件也有头文件的内容,也就是函数定义
这样,在头文件和定义文件同时有一个函数的定义,而且不是重载,所以,就会导致重定义的问题
在编译链接阶段就会报错(事实上是链接link阶段出错)
可是#pragma once不就是解决的重复定义的问题的的吗?
不是,#pragma once处理的是同一个文件重复的宏,也就是头文件,例如间接包含的头文件在预处理编译阶段就会被处理删除掉
但是,现在出现的问题是,在两个文件中,出现了相同的函数,而且不是重载
所以,分离定义的意义是防止编译链接冲突

第二种方式解决:static静态函数


静态函数会改变链接属性,不会进符号表
什么是符号表呢?
就是在编译链接阶段,会把所有文件的函数都集中放到一个叫做符号表的地方
这个是声明定义分离重定义错误的本质
而static静态函数,不会进符号表,只在当前文件内可见

第三种方式:内联函数inline


原理和static是一样的,就是不会把地址放到符号表内,就不会导致冲突

所以,为了解决声明和定义分离的问题,总共有三种方案
同时,小函数用内联inline,大函数用static

相关知识:

auto//自动推导类型


会根据右边的值自动推导数据类型,但是不能用来初始化数据,因为无类型
可以用作函数指针的定义,非常舒服
eg:void (*pf) (inr ,int) = func;
auto pf2  = func;
auto的价值是定义类型比较长的变量
但是auto也有弊端,就是影响阅读性,就是不知道当前变量是什么类型
auto不能作为参数
auto不能定义数组
当前auto可以作为返回值,但是不好用,很坑
因为,如果多个函数嵌套转折使用auto的话,其返回值的类型就很难找到,非常蛋疼

容器for


for(auto e :array)//auto部分也可以使用int、double、char等具体的类型
{
    cout<< e << " ";
}
//e是array的数据的拷贝,改变不了实际的值,要改变可以使用引用:
auto& e//此时e就是array数据的别名,可以进行读写

但是容器for只能用在数组

打印类型:typeid().name

初始化指针用nullptr,而不是NULL
因为NULL在C++98的时候,宏定义为0,有时会出现错误

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

二十5画生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值