概述
文章目录:
- 一、inline函数
- (一)inline函数的概念
- (二)inline函数 && 宏
- (三)inline函数 && static
- (四)inline函数 && 普通函数
- (五)内联函数的缺点及使用建议
- (五)内联函数的限制
- 二、C/C++相互调用
- (一).cpp文件中调用.c文件中的函数
- (二).c文件中调用.cpp文件中的函数
- 1. .cpp源文件允许修改
- 2. .cpp源文件不允许修改
一、inline函数
(一)inline函数的概念
用关键字inline修饰的函数,称为inline函数即内联函数。inline内联函数,在编译阶段,以独立的函数单元编译展开,在调用点直接代码展开,不会(没有必要)生成函数符号,故只有本文件可见。
我们可以通过一段代码来感受一下内联函数的概念:
可以看到:
- 不加内联inline关键字,在定义点将sum函数符号放在函数的.text区,在运行时在*UND*放的声明点的函数符号可以找到一样的函数符号,所以解析成功。
- 加了内联 ,sum函数直接在sum.cpp里面直接展开,不会生成函数符号,那么sum声明点的函数符号无法解析,程序会出错。所以内联函数只有本文件可以用,其他文件不能使用,因为没有函数符号,无法连接到。
(二)inline函数 && 宏
inline内联函数是直接展开在调用点,宏替换也是直接展开替换,那么它们的区别?
- 宏在预编译处理,直接文本替换,无任何检查;
- 内联函数在编译阶段处理,有类型检查和安全检查。所以内联函数是安全的。故可以说内联函数是一种更安全的宏。
(三)inline函数 && static
inline内联函数只能本文件可见,static修饰的函数也是本文件可以使用,那么它们有什么区别呢?
- 内联在调用点直接代码展开,不需要开栈清栈。static修饰的函数,有开栈和清栈的开销。
- 内联不需要生成符号;static需要生成符号,将符号从 global(全局,项目下所有的文件可见)变为local(只有本文件可以见)。
(四)inline函数 && 普通函数
- 普通函数的调用在汇编阶段,需要push压实参指令,call指令调用函数等一系列指令,给函数开辟栈帧,函数运行完成,有函数退出栈帧的过程。
- 内联函数在编译阶段,在函数的调用点将函数的代码展开,省略了函数栈帧开辟回退的调用开销,效率比较高。
- 在debug版本下,内联函数不生效,和普通函数一样,有开栈清栈的过程。
(五)内联函数的缺点及使用建议
内联的效率高,直接代码展开,没有清栈开栈的开销,那么为啥不把所有的函数默认处理为内联函数呢?
如果 内联函数代码过多,那么只要使用内联函数的代码就会变得很庞大,这就是以代码膨胀为代价,以空间换时间的概念。所以内联函数如果代码过多就会导致空间和时间效率都变低。
所以内联 使用建议:
- 如果函数执行的开销<函数开栈清栈的开销,表示函数体简单,那么建议设置为内联函数。
- 如果函数指向开销>函数开栈清栈的开销,那么表示函数体复杂,不建议设置为内联函数。
(五)内联函数的限制
- 内联只在Release版本生效,debug版本不生效,和普通函数一样,有入栈退栈的过程。
- inline只是给编译器的一个建议,是否会处理为内联函数,还是编译器根据当前的代码结构判断 ,一般递归、循环、分支switch编译器不会把它们处理成内联的。
- inline是基于实现的,不是基于声明的。 如果你写到声明点上,声明点展开啥也没有,所以编译器不会处理,它只会去处理在函数定义点的内联。
- 内联的实现要写在头文件.h中,如果写在源文件中,没有调用点,那么无法展开,其他文件有调用点无法使用。只有写在头文件,被包含在其他文件中,在预编译阶段展开后,那么当前源文件中就会出现内联函数的定义,如果有调用点直接调用即可。
二、C/C++相互调用
在一个很大的项目中,可能会有.c文件,.cpp文件,那么c函数可以在.cpp中调用吗,.cpp里的函数可以在.c中调用吗?我们看一下面一段代码,sum.c中有sum函数,main.cpp中声明sum函数,进行调用:
如果我们不做任何处理,肯定是无法调用的,原因很简单,C,C++生成函数符号的规则不同,定义点和调用点的函数符号规则不同,在链接时,无法进行符号重定位,会失败,然后报错。
C/C++无法相互调用的原因是符号生成规则不一样,为了解决这个问题,我们可以让C++代码以C的规则生成函数符号,这样就可以解决问题。那么有两种情况:
(一).cpp文件中调用.c文件中的函数
可以让C++函数声明点采取C的规则生成函数符号,使用 关键字extern "C"
extren "C"
{
CODE
}
将C++文件中C函数的声明包含,表示使用C的处理规则。那么上面的代码可以改为:
extren "C"
{
int sum(int a,int b);//函数符号为_sum
}
含义就是这里面代码的处理方式以C的规则来处理。这样生成规则就会一样,符号解析成功,不会报错,调用成功。
(二).c文件中调用.cpp文件中的函数
就是将sum函数定义放到C++,函数声明放到C中,运行一样会失败。那么有没有extern “C++”这个语法,让C按照C++的规则生成函数符号?
答案:没有,因为C语言先出来,都是遵循向前兼容,即C++可以改善C的缺点,C不能未卜先知C++的缺点。所以不可能存在extern “C++”这个规则。
1. .cpp源文件允许修改
当允许修改.cpp源文件时,处理这个问题还是需要使用extern “C",把C++中的定义点都包含在extern “C”,让它以C的规则生成函数符号放在.text段。
总结来说,就是 函数定义点和声明点如果是因为C、C++语言的原因不同,导致函数符号生成规则不同,那么在C++的部分用extren “C“将其全部包含,这样使得函数符号生成规则一致,不出错。
2. .cpp源文件不允许修改
假设现在一种情况,C++代码无法修改,那么如何能让C、C++代码相互调用不出错呢?
程序员自我修养里有一句话,在计算机科学领域,一切不能直接处理的问题,都可以通过加一个中间层来处理。
那么我们可以在C,C++中加一个中间层,进行一个二次包装,如下图所示:
写个.cpp文件把不能修改的C++函数进行一个调用,这个中间层是我自己加的,那么我当然可以给调用点加个extern “C”,这样C++函数的声明和定义点都是C++规则,但是调用点是C,所以C文件可以使用了,这样C和C++就可以互相兼容了。
加油哦!????。
最后
以上就是魁梧玫瑰为你收集整理的【C++】四、inline函数、C/C++相互调用的全部内容,希望文章能够帮你解决【C++】四、inline函数、C/C++相互调用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复