欢迎光临散文网 会员登陆 & 注册

C++自制心得——开篇(内联函数)

2023-08-20 16:12 作者:这年头起名可真不容易  | 我要投稿

前言: 

本心得只适合给那些拥有C语言基础 (系统的自主学习过C语言(以找工作为目标,学校老师教的一律视作没学)),了解一些底层机制,用C实现过一些基本数据结构 (顺序表、链表、队列与栈、初等二叉树、十大经典排序等) ) 的人观看。如果你不满足上述条件就不要在这里浪费时间了。

本人在写专栏上的技术力并不好,如果你觉得这篇文章在排版上有需要改进的地方可以在评论区留言并附上具体操作流程。

本人目前是大二在读生,目前刚开始学习C++相关知识,如果有大佬发现哪里介绍的不对或者有疏漏欢迎在评论区留言,我尽量在发现的第一时间纠正。

好,废话不多讲,我们进入正题。

内联函数

1. 宏函数与内联函数

在开始我们正式讲解之前,先问一个小问题,怎么用宏函数写一个Add?哎呀写个Add,这不是章口就......?宏函数,我想想,应该是这样的。

好像不对,哦,我想起来了,宏是替换,不能加分号。

感觉...还少了点什么,对,差一个括号。

完美,调试也没出问题,就它了。

but,这还是错的,正确的写法是这样的。

它为什么这么写,我相信大家心里都有数。但我估计如果不给正确示范老司机可能也会翻车。这就说明了宏函数的第一个问题,容易出现语法错误。宏函数的第二个问题就是无法调试,更坑人。但宏函数也有一些好处,第一,没有类型检查更灵活,不过在后面我们会学模板,这个优势就等于不存在。第二,节省函数栈帧调用所导致的时间消耗。所以,为了解决宏函数的缺陷,内联函数应运而生。

这就是一个简单的内联函数的代码,只需要在函数前面加上inline关键字就可以了。

内联函数解决了宏函数的所有问题,并保留了其可原地展开的优点。首先,内联函数不可能写出像宏一样的语法问题,因为内联函数除了前面的关键字,其余部分与函数完全一样,而函数是我们早就写烂的东西。其次,如果没有人为修改编译器设置,内联函数在debug模式下可以像常规函数一样调试,只有在release模式下才会和宏一样原地展开。

默认情况下内联函数在debug模式下的汇编代码
修改编译器设置后在debug模式里调出来的内联函数的汇编代码

对比一二两张图,很明显第二张图里没有call语句(常规函数调用的关键指令),这说明使用内联函数确实不会建立函数栈帧。

2. 内联函数的特性

这里要强调一点,inline关键字只是一个请求,不是强制性的,也就是说,一个函数是不是内联函数需要经过编译器审核,一般情况下过长的函数不会成为内联函数,举个例子:

看见那个醒目的call没有

让我们把代码改短一点

编译器这么做自然有它的理由,这里我们假设编译器不会检查内联函数展开后的汇编指令数目,再定义一个函数void func(),假设它展开有10000行汇编指令(假定函数在调用处展开与建立函数栈帧生成的汇编指令数相同(以这个函数的体量来说,这点不同完全可以忽略)),分别以内联函数与常规函数的形式调用100次,那么以常规函数形式调用只有10100行汇编指令(每个调用处只有一句call指令),以内联函数形式调用就会在每个调用处生成10000行汇编指令,加在一起就是1000000行,相差近100倍。这就会导致一个问题------代码膨胀,最近原神不是新出了一个枫丹压缩包,据说解压后有60G,经过这样的反向优化说不定就变成了80个G,得不偿失。

其次,内联函数的声明与定义与一般函数有所不同。

声明和定义在同一文件内当然没有问题

常规的跨文件调用会出现链接错误。

test.cpp

test.h

inline.cpp

再来另一段代码

test.cpp(修改后)

test.h(修改后)

inline.cpp(修改后)

这怎么就过了,上面的怎么就不行。还记得我们在内联函数与常规函数最大的区别吗?不需要call指令,这就意味着内联函数的地址并不需要进入符号表(call指令调用函数要用到函数地址),编译器也是这么做的。但是,我们把内联函数的声明与定义装到了两个不同的文件里,因此,链接器只能被迫在符号表里寻找内联函数的地址,结果可想而知,找不到。

在修改后的版本里,我们没有直接跨文件调用内联函数,而是通过常规函数作为桥梁,间接达到了跨文件调用内联函数的效果。不过,这个方案很挫,下面才是真正的解决方案。

test.h(二次再版)

inline.cpp(二次再版)

原理很简单,既然内联函数不能跨文件调用,那统一在文件内调用不就行了,结果确实符合预期。

而且,因为内联函数不进入符号表的特性,因头文件被多个源文件包含所导致的链接冲突问题并不会发生。

别急,再讲一个运算符重载,我们就有对象了,待会见。

C++自制心得——开篇(内联函数)的评论 (共 条)

分享到微博请遵守国家法律