首页 > 其他分享 >C语言inline关键字

C语言inline关键字

时间:2022-11-15 17:25:51浏览次数:41  
标签:函数 int C语言 关键字 编译器 内联 inline

一、inline关键字的概念

inline关键字是C99标准的型关键字,其作用是将函数展开,把函数的代码复制到每一个调用处。这样调用函数的过程就可以直接执行函数代码,而不发生跳转、压栈等一般性函数操作。可以节省时间,也会提高程序的执行速度。

二、为什么需要内联函数

在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)?”奇”:”偶”这样就避免了频繁调用函数对栈内存重复开辟所带来的消耗。

三、内联函数的编程风格

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

例如,下面风格的函数fun将不能成为内联函数:

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

}

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

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

}

2、关键字inline的使用是有所限制的

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

3. inline仅是一个对编译器的建议

inline函数仅仅是一个对编译器的建议,所以最后能否真正内联,看编译器的意思,它如果认为函数不复杂,能在调用点展开,就会真正内联,并不是说声明了内联就会内联,声明内联只是一个建议而已。

4. 建议:inline函数的定义放在头文件中

其次,因为内联函数要在调用点展开,所以编译器必须随处可见内联函数的定义,要不然就成了非内联函数的调用了。所以,这要求每个调用了内联函数的文件都出现了该内联函数的定义

因此,将内联函数的定义放在头文件里实现是合适的,省却你为每个文件实现一次的麻烦。

声明跟定义要一致:如果在每个文件里都实现一次该内联函数的话,那么,最好保证每个定义都是一样的,否则,将会引起未定义的行为。如果不是每个文件里的定义都一样,那么,编译器展开的是哪一个,那要看具体的编译器而定。所以,最好将内联函数定义放在头文件中。

5. 慎用inline

内联能提高函数的执行效率,为什么不把所有的函数都定义成内联函数?如果所有的函数都是内联函数,还用得着“内联”这个关键字吗?
内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。 如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。

以下情况不宜使用内联:
(1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高
(2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构函数可能会隐藏一些行为,如“偷偷地”执行了基类或成员对象的构造函数和析构函数。所以不要随便地将构造函数和析构函数的定义体放在类声明中。一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明了 inline 不应该出现在函数的声明中)。

6、static和inline联合使用

static是静态修饰符,由其关键字修饰的变量会保存到全局数据区,对于普通的局部变量或者全局变量,都是由系统自动分配内存的,并且当变量离开作用域的时候释放掉,而使用static关键字来修饰,只有当程序结束时候才会释放掉,使用static inline修饰时,函数仅在文件内部可见,不会污染命名空间,另外,函数在运行过程中也会分配内存空间,但是由于static的存在,就和修饰变量类似,它只会开辟一块内存空间。

6、inline函数在某种程度上来讲很像带参数的宏

虽然inline函数和带参数的宏很像,但是在使用方法上和宏还是有很大区别的:

inline函数和带参数的宏的区别

  inline()函数 带参数的宏
展开的时机 在编译的时候展开,因此inline关键字是一个编译关键字 在预处理时展开,因此#define关键字是一个预处理关键字
参数类型检查 inline()函数是一中函数,会进行严格的参数类型检查 不会检查参数类型,只是做简单的字符串替换,因此在使用带参数的宏时会有一些副作用,编写程序是要人为预防
是否允许有复杂语句 不允许出现复杂语句,如果出现复杂语句,该函数将不会展开,例如递归,大型循环等 对此不做要求。宏只是做字符串替换操作,而不了解语句的含义
是否一定被展开 不一定,是否展开由编译器决定 一定,只要使用了宏就可以保证被展开

inline和#define的区别:

inline由编译器一起处理,直接将比那以后的函数体插入调用的地方。

#define由预处理器处理,进行简单的文本替换,没有任何编译过程。

标签:函数,int,C语言,关键字,编译器,内联,inline
From: https://www.cnblogs.com/amxiang/p/16893085.html

相关文章

  • 初学C语言
    注意事项:1)C程序的主体结构说明:#include...viodmain(){//{}包括内容,成为函数体语句1;语句2}2)源文件以“c”为扩展名3)执行入口是main()方法4)严格区分大小写5)每句以......
  • this和super关键字
    this关键字this的本质就是:创建好的对象的地址->代表当前对象构造方法是创建java对象的重要途经,通过new关键字调用构造器时,构造器返回该类对象,但是该对象并不完全由构......
  • 计算机等级考试二级C语言程序设计专项训练题——程序填空题(一)
    1、下列给定程序中,函数fun的功能是:把形参a所指数组中的偶数按原顺序依次存放到a[0]、a[1]、a[2]…中,把奇数从数组中删除,偶数的个数通过函数值返回。例如,若a所指数组中的数据......
  • 抽象类、abstract关键字
    目录abstract关键字抽象类的匿名子类抽象类的应用:模板方法的设计模式abstract关键字abstract:抽象的abstract可以用来修饰的结构:类、方法abstract修饰类:抽象类此类......
  • 接口、interface关键字
    目录interface关键字接口的匿名实现类的对象接口的应用:代理模式JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法面试题:抽象类与接口有哪些异同?interface......
  • 代码块、final关键字
    目录代码块final关键字代码块代码块的作用:用来初始化类、对象代码块如果有修饰的话,只能使用static分类:静态代码块vs非静态代码块静态代码块: 内部可以有输......
  • static关键字
    static关键字static:静态的static可以用来修饰:属性、方法、代码块、内部类使用static修饰属性:静态变量(或类变量)属性,按是否使用static修饰,又分为:静态属性vs非静态属......
  • 多态性、instanceof关键字
    目录多态性向下转型instanceof关键字多态性理解多态性:可以理解为一个事物的多种形态。何为多态性:对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)多......
  • 2022级信息工程学院《C语言程序设计》阶段1考试
    ProblemA:七进制转换Solution要认真读题的题正经讲过无数次的进制转换,不断取mod做除法判断素数,\(2\)~\(\sqrt{n}\)有能除尽的是合数,否则是质数注意审题,“在此将......
  • 重写、super关键字
    目录重写super关键字重写重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作。重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,......