inline这个函数也一直在用,但是不知道什么时候用的恰当?借此机会复习

一、什么是内联函数

       在C语言中,如果一些函数被频繁调用,不断地有函数入栈,即函数栈,会造成栈空间或栈内存的大量消耗。

       为了解决这个问题,特别的引入了inline修饰符,表示为内联函数。

       栈空间就是指放置程式的局部数据也就是函数内数据的内存空间,在系统下,栈空间是有限的,假如频繁大量的使用就会造成因栈空间不足所造成的程式出错的问题,函数的死循环递归调用的最终结果就是导致栈内存空间枯竭。

下面我们来看一个例子:

#include <stdio.h>  
 
//函数定义为inline即:内联函数  
inline char* dbtest(int a)
{  
    return (i % 2 > 0) ? "奇" : "偶";  
}   
 
int main()  
{  
    int i = 0;  
    for (i=1; i < 100; i++)
    {  
        printf("i:%d    奇偶性:%s /n", i, dbtest(i));      
    }  
}

上面的例子就是标准的内联函数的用法,使用inline修饰带来的好处我们表面看不出来,其实在内部的工作就是在每个for循环的内部任何调用dbtest(i)的地方都换成了(i%2>0)?"奇":"偶"这样就避免了频繁调用函数对栈内存重复开辟所带来的消耗。

     其实这种有点类似咱们前面学习的动态库和静态库的问题,使 dbtest 函数中的代码直接被放到main 函数中,执行for 循环时,会不断调用这段代码,而不是不断地开辟一个函数栈。

二、内联函数的编程风格

 

1、关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用

如下风格的函数Foo 不能成为内联函数:

inline void Foo(int x, int y); // inline 仅与函数声明放在一起
void Foo(int x, int y)
{
}

而如下风格的函数Foo 则成为内联函数:

void Foo(int x, int y);
inline void Foo(int x, int y) // inline 与函数定义体放在一起
{
}

   所以说,inline 是一种 “用于实现的关键字” ,而不是一种“用于声明的关键字”。一般地,用户可以阅读函数的声明,但是看不到函数的定义。尽管在大多数教科书中内联函数的声明、定义体前面都加了inline 关键字,但我认为inline 不应该出现在函数的声明中。这个细节虽然不会影响函数的功能,但是体现了高质量C++/C 程序设计风格的一个基本原则:声明与定义不可混为一谈,用户没有必要、也不应该知道函数是否需要内联。

 

 

2、inline的使用是有所限制的

 

      inline只适合涵数体内代码简单的函数数使用,不能包含复杂的结构控制语句例如while、switch,并且内联函数本身不能是直接递归函数(自己内部还调用自己的函数)。

三、慎用内联

  内联能提高函数的执行效率,为什么不把所有的函数都定义成内联函数?如果所有的函数都是内联函数,还用得着“内联”这个关键字吗?

       内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收
获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。

以下情况不宜使用内联:

(1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。

(2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。

一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明了inline 不应该出现在函数的声明中)。

 

四、内联函数取代宏定义

上面说了一种内联函数引入的原因是减小函数栈空间的频繁调用,下面还有一种解释:用它替代C中的表达式形式的宏定义

例如:#define ExpressionName(Var1,Var2) ((Var1)+(Var2))*((Var1)-(Var2))

为什么要用这么难看且不友好的形式呢?

 

1. 首先谈一下在C中使用这种形式宏定义的原因,C语言是一个效率很高的语言,这种宏定义在形式及使用上像一个函数,但它使用预处理器实现,没有了参数压栈,代码生成等一系列的操作,因此,效率很高,这是它在C中被使用的一个主要原因。

 

2. 这种宏定义在形式上类似于一个函数,但在使用它时,仅仅只是做预处理器符号表中的简单替换,因此它不能进行参数有效性的检测也就不能享受C++编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的类型,这样,它的使用就存在着一系列的隐患和局限性。

 

3. 在C++中引入了类及类的访问控制,这样,如果一个操作或者说一个表达式涉及到类的保护成员或私有成员,你就不可能使用这种宏定义来实现(因为无法将this指针放在合适的位置)。

 

4. inline 推出的目的,也正是为了取代这种表达式形式的宏定义,它消除了宏定义的缺点,同时又很好地继承了宏定义的优点

除了inline函数的好处,在使用时我们还需要遵循一下几个规则:

 

规则一:一个函数可以自已调用自已,称为递归调用(后面讲到),含有递归调用的函数不能设置为inline。

 

规则二:使用了复杂流程控制语句:循环语句和switch语句,无法设置为inline。

 

规则三:由于inline增加体积的特性,所以建议inline函数内的代码应很短小。最好不超过5行。

 

规则四:inline仅做为一种“请求”,特定的情况下,编译器将不理会inline关键字,而强制让函数成为普通函数。出现这种情况,编译器会给出警告消息。(也就是说程序员定义为内联,编译器觉得不合适会给修改成普通函数)

 



原文链接:https://blog.csdn.net/zqixiao_09/article/details/50877383

https://www.cnblogs.com/sinpoo/p/3413338.html

 

posted on 2023-03-02 11:28  shiyuan310  阅读(86)  评论(0编辑  收藏  举报