内联函数
内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处。编译时,类似宏替换,使用函数体替换调用处的函数名。一般在代码中用inline修饰,但是能否形成内联函数,需要看编译器对该函数定义的具体处理。
"},{"rawTitle":"动机","property":1,"id":2,"title":"动机","content":"内联扩展是用来消除函数调用时的时间开销。它通常用于频繁执行的函数。一个小内存空间的函数非常受益。
如果没有内联函数,编译器可以决定哪些函数内联。程序员很少或没有控制哪些只能是内联的,哪些不是。给这种控制程度,作用是程序员可以选择内联的特定应用。
"},{"rawTitle":"内联问题","property":1,"id":3,"title":"内联问题","content":"除了相关的问题,内联扩展一般,语言功能作为一个内联函数可能不被视为有价值的,因为它们出现的原因,对于一个数字:
通常,一个编译器是在一个比人类更有利的地位来决定某一特定功能是否应该被内联。有时,编译器可能无法尽可能多的功能内嵌作为程序员表示。
一个重要的一点需要注意的是代码(内联函数)得到暴露其客户端(调用函数)。
随着功能的演变,它们有可能成为合适的内联,他们不前,或不再在他们面前的内联合适。而内联或取消内联函数比从宏转换为更容易,但仍需要额外的维修,一般产量相对较少的利益。
用于本机C型编译系统的扩散可以增加编译时间,因为他们的身体的中间表示是到每个调用点,他们都是内联复制内联函数。在代码大小可能增加是由在编译时间可能增加镜像。
C99中内嵌的规范要求只有一个额外在另一个编译单元,功能的外部定义时,相应的内联定义,可以发生在不同的编译单元多次,如果该函数用于地方。这很容易导致连接器,因为这样的定义不是由程序员提供的错误。出于这个原因,往往是在C99内联一起使用静态的,也给出了函数的内部联系。
在C++,有必要定义一个在每一个模块(编译单元)内联函数使用一个普通的功能,而必须在只有一个模块中定义它。否则,就不可能编制的所有其他模块一个模块独立。
对于功能问题与优化本身,而不是语言,请参阅使用内联扩展问题。
内联函数是使用inline关键字声明的函数,也成内嵌函数,它主要的作用是解决程序的运行效率。
使用内联函数的时候要注意:
1.递归函数不能定义为内联函数
2.内联函数一般适合于不存在while和switch等复杂的结构且只有1~5条语句的小函数上,否则编译系统将该函数视为普通函数。
3.内联函数只能先定义后使用,否则编译系统也会把它认为是普通函数。
4.对内联函数不能进行异常的接口声明。
"},{"rawTitle":"行情","property":1,"id":4,"title":"行情","content":"“一个函数声明[。。。]说明符声明一个内联与内联函数。内联说明符指示的实现,内联函数体替代了在调用点是首选通常的函数调用机制。一个实现不要求在调用执行此点内联替代,但是,即使这个内嵌替代省略,由7.1.2内联函数定义的其他规则,仍应得到尊重“。
“的函数说明符声明的内联函数是一个内联函数。[。。。]制作一个内联函数的函数表明该函数被调用尽可能快。在何种程度上这些建议是有效的,是实现定义(注:例如,一个实施内联替换可能不会执行,或者可能只执行替换内联在声明中要求的范围内联的)。
“[。。。]内联定义不提供外部定义的功能,并且不禁止的定义,还有一个是外部的翻译单位。一个内联定义提供了任何其他的外部定义,翻译可能用来实现呼吁在相同的翻译单元的功能。没有指定是否调用该函数内联定义或使用外部定义。”
-国际标准化组织9899:1999(E)的C99标准,第6.7.4
"},{"rawTitle":"宏比较","property":1,"id":5,"title":"宏比较","content":"内联函数的功能和预处理宏的功能相似。相信大家都用过预处理宏,我们会经常定义一些宏,如
#defineTABLE_COMP(x)((x)>0?(x):0)
就定义了一个宏。
为什么要使用宏呢?因为函数的调用必须要将程序执行的顺序转移到函数
所存放在内存中的某个地址,将函数的程序内容执行完后,再返回到转去执行
该函数前的地方。这种转移操作要求在转去执行前要保存现场并记忆执行的地
址,转回后要恢复现场,并按原来保存地址继续执行。因此,函数调用要有一
定的时间和空间方面的开销,于是将影响其效率。而宏只是在预处理的地方把
代码展开,不需要额外的空间和时间方面的开销,所以调用一个宏比调用一个
函数更有效率。
但是宏也有很多的不尽人意的地方。
1、.宏不能访问对象的私有成员。
2、.宏的定义很容易产生二义性。
我们举个例子:
#defineTABLE_MULTI(x)(x*x)
我们用一个数字去调用它,TABLE_MULTI(10),这样看上去没有什么错误,
结果返回100,是正确的,但是如果我们用TABLE_MULTI(10+10)去调用的话,
我们期望的结果是400,而宏的调用结果是(10+10*10+10),结果是120,这显
然不是我们要得到的结果。避免这些错误的方法,一是给宏的参数都加上括号。
#defineTABLE_MULTI(x)((x)*(x))
这样可以确保不会出错,但是,即使使用了这种定义,这个宏依然有可能
出错,例如使用TABLE_MULTI(a++)调用它,他们本意是希望得到(a+1)*(a+1)的
结果,而实际上呢?我们可以看看宏的展开结果:(a++)*(a++),如果a的值是
4,我们得到的结果是4*4=16,a=6。而我们期望的结果是4*4=16,而a=5,这又出现了问题。
事实上,在一些C的库函数中也有这些问题。例如:Toupper(*pChar++)就会对
pChar执行两次++操作,因为Toupper实际上也是一个宏。
我们可以看到宏有一些难以避免的问题,怎么解决呢?
下面就是用我要介绍的内联函数来解决这些问题,我们可以使用内联函数
来取代宏的定义。而且事实上我们可以用内联函数完全取代预处理宏。
内联函数和宏的区别在于,宏是由预处理器对宏进行替代,而内联函数是
通过编译器控制来实现的。而且内联函数是真正的函数,只是在需要用到的时
候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开
销。你可以象调用函数一样来调用内联函数,而不必担心会产生于处理宏的一
些问题。
我们可以用Inline来定义内联函数,不过,任何在类的说明部分定义的函
数都会被自动的认为是内联函数。
下面我们来介绍一下内联函数的用法。
内联函数必须是和函数体申明在一起,才有效。像这样的申明InlineTablefunction(intI)是没有效果的,编译器只是把函数作为普通的函数申明,我们必须定义函数体。
Inlinetablefunction(intI){returnI*I}
附件列表
本站全部内容禁止商业使用。文本内容除另有声明外,均在知识共享 署名-非商业性使用-相同方式共享 3.0 中国大陆(CC BY-NC-SA 3.0 CN)许可协议下提供。