【C++】内联函数

【C++】内联函数

1、内联函数概念

函数是一个可以重复使用的代码块,CPU 会一条一条地挨着执行其中的代码。CPU 在执行主调函数代码时如果遇到了被调函数,主调函数就会暂停,CPU 转而执行被调函数的代码;被调函数执行完毕后再返回到主调函数,主调函数根据刚才的状态继续往下执行。

一个 C/C++程序的执行过程可以认为是多个函数之间的相互调用过程,它们形成了一个或简单或复杂的调用链条,这个链条的起点是 main(),终点也是 main()。当 main() 调用完了所有的函数,它会返回一个值(例如return 0;)来结束自己的生命,从而结束整个程序。

函数调用是有时间和空间开销的。程序在执行一个函数之前需要做一些准备工作,要将实参、局部变量、返回地址以及若干寄存器都压入栈中,然后才能执行函数体中的代码;函数体中的代码执行完毕后还要清理现场,将之前压入栈中的数据都出栈,才能接着执行函数调用位置以后的代码。

如果函数体代码比较多,需要较长的执行时间,那么函数调用机制占用的时间可以忽略;如果函数只有一两条语句,那么大部分的时间都会花费在函数调用机制上,这种时间开销就就不容忽视。

为了消除函数调用的时空开销,C++ 提供一种提高效率的方法,即在编译时将函数调用处用函数体替换,类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数称为内联函数(Inline Function),又称内嵌函数或者内置函数。

2、内联函数的特性

1)空间换时间,因为反复调用内联函数,导致编译出来的可执行程序变大

2)编译器可以忽略内联请求,内联函数被忽略的界限没有被规定,一般10行以上就被认为是长函数,不同的编译器不同

3)内联函数声明和定义不可分离

2.1 空间与时间

inline void test()
{
    ...//编译为10条指令
}

若不用内联函数,不展开,若1000次调用 func,每次调用的地方为 call 指令的形式,总计 1010 行指令。若用内联函数,则展开,若一千次调用,每次调用的地方为都会展开为 10 条指令,总计 10 * 1000 行指令。

展开会让编译后的程序变大,如果递归函数作内联,后果可想而知。所以长函数和递归函数不适合展开

2.2 忽略的内联函数

一句话:简短,频繁调用的小函数建议定义成 inline

2.3 声明和定义

由于内联函数在调用的地方展开,所以内联函数无地址(这里的地址指的是call 指令调用函数的地址,通过这个地址会跳到 jmp 指令处,再根据 jmp 处指令跳转到函数执行的部分)

当编译时,由于头文件要被包含,但是这时只有函数声明,但是没有函数的定义,所以只能在链接时展开,这里只能变为 call + 地址的指令,但是内联函数并没有地址,无法链接,报错。

所以当声明和定义分离,调用函数时,由于内联函数无地址,编译器链接不到,所以就会报错,为链接错误

3、总结

内联能提高函数的执行效率,那么为什么不把所有的函数都定义成内联函数呢?

内联不是万灵丹,它以代码膨胀(拷贝)为代价,仅仅省去了函数调用的开销,从而提高程序的执行效率。(开销指的是参数的压栈、跳转、退栈和返回操作)。

  • 一方面,如果执行函数体内代码的时间比函数调用的开销大得多,那么inline效率收益会很小。
  • 另一方面,每一处内联函数的调用都要拷贝代码,使程序的总代码量增大,消耗更多的内存空间。

以下情况不宜使用内联:

  • 如果函数体内代码比较长,使用内联将导致可执行代码膨胀过大。
  • 如果函数体内出现循环或者其他复杂的控制结构,那么执行函数体内代码的时间将比函数调用的开销大得多。
    内联将导致可执行代码膨胀过大。
  • 如果函数体内出现循环或者其他复杂的控制结构,那么执行函数体内代码的时间将比函数调用的开销大得多。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值