内联函数 —— C 中关键字 inline 用法解析

一、什么是内联函数

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

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

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

下面我们来看一个例子:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>    
  2.   
  3. //函数定义为inline即:内联函数    
  4. inline char* dbtest(int a)   
  5. {    
  6.     return (i % 2 > 0) ? "奇" : "偶";    
  7. }     
  8.     
  9. int main()    
  10. {    
  11.     int i = 0;    
  12.     for (i=1; i < 100; i++)   
  13.     {    
  14.         printf("i:%d    奇偶性:%s /n", i, dbtest(i));        
  15.     }    
  16. }   

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

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


二、内联函数的编程风格

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

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

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. inline void Foo(int x, int y); // inline 仅与函数声明放在一起  
  2. void Foo(int x, int y)  
  3. {  
  4. }  

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

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. void Foo(int x, int y);  
  2. inline void Foo(int x, int y) // inline 与函数定义体放在一起  
  3. {  
  4. }  
       所以说,inline 是一种 “用于实现的关键字” ,而不是一种“用于声明的关键字”。一般地,用户可以阅读函数的声明,但是看不到函数的定义。尽管在大多数教科书中内联函数的声明、定义体前面都加了inline 关键字,但我认为inline 不应该出现在函数的声明中。这个细节虽然不会影响函数的功能,但是体现了高质量C++/C 程序设计风格的一个基本原则:声明与定义不可混为一谈,用户没有必要、也不应该知道函数是否需要内联。


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

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


三、慎用内联

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

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

以下情况不宜使用内联:

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

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

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


总结:

       因此,将内联函数放在头文件里实现是合适的,省却你为每个文件实现一次的麻烦.而所以声明跟定义要一致,其实是指,如果在每个文件里都实现一次该内联函数的话,那么,最好保证每个定义都是一样的,否则,将会引起未定义的行为,即是说,如果不是每个文件里的定义都一样,那么,编译器展开的是哪一个,那要看具体的编译器而定.所以,最好将内联函数定义放在头文件中. 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/401946.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

eclipse maven scm

http://my.oschina.net/OutOfMemory/blog/178512 1.安装eclipse的maven插件 m2e(http://wiki.eclipse.org/M2E_updatesite_and_gittags)Help->Install New Software...在work with中填入我们需要安装m2e的版本url&#xff1a;http://download.eclipse.org/technology/m2e/…

DS18B20 驱动编写

嵌入式开发平台&#xff1a;mini2440 DS18B20 所用GPIO&#xff1a;S3C2410_GPF(3) 一、DS18B20 时序分析 DS18B20的一线工作协议流程是&#xff1a;初始化→ROM操作指令→存储器操作指令→数据传输&#xff0c;其工作时序包括&#xff1a;初始化时序、写时序、读时序。 1、初…

Android 自定义View实现画背景和前景(ViewGroup篇)

2019独角兽企业重金招聘Python工程师标准>>> 在定义ListView的Selector时候&#xff0c;有个drawSelectorOnTop的属性&#xff0c;如果drawSelectorOnTop为true的话&#xff0c;Selector的效果是画在List Item的上面&#xff08;Selector是盖住了ListView的文字或者…

Linux的mmap内存映射机制解析

在讲述文件映射的概念时,不可避免的要牵涉到虚存(SVR 4的VM).实际上,文件映射是虚存的中心概念, 文件映射一方面给用户提供了一组措施,好似用户将文件映射到自己地址空间的某个部分,使用简单的内存访问指令读写文件&#xff1b;另一方面,它也可以用于内核的基本组织模式,在这种…

svn add Default@2x.png的文件含有@的文件名注意事项

为什么80%的码农都做不了架构师&#xff1f;>>> iOS的Icon里面&#xff0c;包含符号 &#xff0c;svn add Icon2x.png&#xff0c;没法加进去。 解决的办法是&#xff0c;在文件名最后加一个&#xff0c;例如 svn add Icon2x.png 或者svn add Icon\2x.png\ 转载于…

Linux 设备驱动的固件加载

作为一个驱动作者, 你可能发现你面对一个设备必须在它能支持工作前下载固件到它里面. 硬件市场的许多地方的竞争是如此得强烈, 以至于甚至一点用作设备控制固件的 EEPROM 的成本制造商都不愿意花费. 因此固件发布在随硬件一起的一张 CD 上, 并且操作系统负责传送固件到设备自身…

ORM for Net主流框架汇总与效率测试

框架已经被越来越多的人所关注与使用了&#xff0c;今天我们就来研究一下net方面的几个主流ORM框架&#xff0c;以及它们的效率测试&#xff08;可能会有遗漏欢迎大家讨论&#xff09;。 ORM框架&#xff1a;Object/Relation Mapping&#xff08;对象/关系 映射&#xff09;的缩…

Yii基于角色的访问控制(非Rbac)

今天遇到了权限控制的问题&#xff0c;后台不同级别的用户登录后看到的内容是不一样的。网上查了下&#xff0c;说Yii中有自带的RBAC权限控制&#xff0c;大概看了下&#xff0c;没理解太明白。然后就是采用filter进行过滤验证&#xff0c;看着这个还不错。下面简单说下我是我怎…

Linux USB 驱动开发(二)—— USB 驱动几个重要数据结构

前面我们学习了USB 驱动的一个描述符&#xff0c;下面来学习 USB 驱动的几个重要数据结构 一、struct usb_interface 接口函数 [cpp] view plaincopy struct usb_interface { struct usb_host_interface *altsetting; struct usb_host…

比较DataTable中新旧数据

内容不写了&#xff0c;代码上都做了写注释。1 /** <summary> 2 /// 比较两个数据表&#xff0c;并返回比较结果表 3 /// 比较条件&#xff1a; 4 /// 1.两个表结构相同&#xff1b; 5 /// 2.两个表排序都是按主键顺序排序&#xff1b…

Linux USB 驱动开发(三)—— 编写USB 驱动程序

前面学习了USB驱动的一些基础概念与重要的数据结构&#xff0c;那么究竟如何编写一个USB 驱动程序呢&#xff1f;编写与一个USB设备驱动程序的方法和其他总线驱动方式类似&#xff0c;驱动程序把驱动程序对象注册到USB子系统中&#xff0c;稍后再使用制造商和设备标识来判断是否…

病毒式推广最终可能会走到尽头

Buzzfeed自称是社交时代的媒体(The Media of Social Age)&#xff0c;而HuffingtonPost是为搜索引擎创作的。我们也曾经读过《 Believe Me, I’m Lying》这样的关于如何通过博客操纵媒体的书。在社交时代&#xff0c;资讯会发生什么样的变化&#xff1f;FT 约翰•加普的文章为我…

Linux USB 驱动开发(一)—— USB设备基础概念

在终端用户看来&#xff0c;USB设备为主机提供了多种多样的附加功能&#xff0c;如文件传输&#xff0c;声音播放等&#xff0c;但对USB主机来说&#xff0c;它与所有USB设备的接口都是一致的。一个USB设备由3个功能模块组成&#xff1a;USB总线接口、USB逻辑设备和功能单元&am…

struts.properties文件

这个文件提供了一种更改框架默认行为方式的机制。通常&#xff0c;我们为了使调试更加方便&#xff0c;我们在这个文件中自定义属性。在“struts.properties”文件中定义的属性都可以在“web.xml”文件的“init-param”标签中进行配置&#xff0c;或者通过“struts.xml”文件中…

Linux USB 驱动开发(四)—— 热插拔那点事

学习USB热插拔之前&#xff0c;先学习一些USB的硬件知识&#xff1a; 一、USB基础概念 1、硬件知识&#xff08;USB插座和插头&#xff09; 在最初的标准里&#xff0c;USB接头有4条线&#xff1a;电源&#xff0c;D-,D,地线。我们暂且把这样的叫做标准的USB接头吧。后来OTG出现…

最近新学的小东西和单词

Scheme //Schema概要, 计划, 图表 content: attr(title); //从属性中拿title作为内容 ,这个是CSS3的样式可以这样子写 //pushstate的用法 <html> <script> for(i0;i<5;i){var stateObject {id: i};var title "Wow Title "i;var newUrl "/my/a…

Linux USB 驱动开发(五)—— USB驱动程序开发过程简单总结

设备驱动程序是操作系统内核和机器硬件之间的接口&#xff0c;由一组函数和一些私有数据组成&#xff0c;是应用程序和硬件设备之间的桥梁。在应用程序看来&#xff0c;硬件设备只是一个设备文件&#xff0c;应用程序可以像操作普通文件一样对硬件设备进行操作。 设备驱动程序是…

android软键盘上推ui解决

为什么80%的码农都做不了架构师&#xff1f;>>> http://bbs.csdn.net/topics/340198955 android软键盘上推ui解决 good job 转载于:https://my.oschina.net/macleo/blog/204882

Linux USB 驱动开发实例(一) —— USB摄像头驱动实现源码分析

Spac5xx的实现是按照标准的USB VIDEO设备的驱动框架编写&#xff08;其具体的驱动框架可参照/usr/src/linux/drivers/usb/usbvideo.c文件&#xff09;&#xff0c;整个源程序由四个主体部分组成&#xff1a; 设备模块的初始化模块和卸载模块&#xff0c;上层软件接口模块&#…

System Center 2012R2之SCVMM云部署SCOM(2-2)

SCVMM云部署SCOM安装过程1、在SCVMM中&#xff0c;使用WINDOWS SERVER 2012母盘创建云主机SCOM在SCVMM中先创建到一个私有云指定一个私有云名称选择资源主机指定逻辑网络默认选负载衡器跳过VIP模板跳过选择端口&#xff0c;下一步选择存储分类指定存储的VM路径各只读共享默认设…