条款33: 明智地使用内联

调用函数实际上将程序执行顺序转移到函数所存放在内存中某个地址,将函数的程序内容执行完后,再返回到转去执行该函数前的地方。这种转移操作要求在转去前要保护现场并记忆执行的地址,转回后先要恢复现场,并按原来保存地址继续执行。

当程序运行到某个节点时,如果发现有函数调用语句(函数要事先声明或者事先定义),程序就自动保存当前程序运行的各个参数、变量到堆栈中去,然后利用所给函数参数调用该函数并运行得出结果,并且将结果保存到内存寄存器中,然后程序自动返回函数调用前的节点处,再将堆栈中的数据出栈,然后再继续运行后面的程序!(其实质就是压栈然后再出栈的操作。当程序检测到有函数调用语句时,自动将汇编语言的中断程序复制到相应的代码段并执行)  

因此,函数调用要有一定的时间和空间方面的开销,于是将影响其效率。特别是对于一些函数体代码不是很大,但又频繁地被调用的函数来讲,解决其效率问题更为重要。引入内联函数实际上就是为了解决这一问题。

在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来进行替换。显然,这种做法不会产生转去转回的问题,但是由于在编译时函数体中的代码被替代到程序中,因此会增加目标程序代码量,进而增加空间开销,而在时间开销上不象函数调用时那么大,可见它是以目标代码的增加为代价来换取时间的节省。

在程序中,调用内联函数时,该函数在编译时被替代,而不是像一般函数那样是在运行时被调用。

内联函数的基本思想在于将每个函数调用以它的代码体来替换,这种做法很可能会增加整个目标代码的体积。在一台内存有限的计算机里,过分地使用内联所产生的程序会因为有太大的体积而导致可用空间不够。即使可以使用虚拟内存,内联造成的代码膨胀也可能会导致不合理的页面调度行为(系统颠簸),这将使你的程序运行慢得象在爬。过多的内联还会降低指令高速缓存的命中率,从而使取指令的速度降低,因为从主存取指令当然比从缓存要慢。

另一方面,如果内联函数体非常短,编译器为这个函数体生成的代码就会真的比为函数调用生成的代码要小许多。如果是这种情况,内联这个函数将会确实带来更小的目标代码和更高的缓存命中率!

要牢记在心的一条是,inline指令就象register,它只是对编译器的一种提示,而不是命令。也就是说,只要编译器愿意,它就可以随意地忽略掉你的指令,事实上编译器常常会这么做。例如,大多数编译器拒绝内联"复杂"的函数(例如,包含循环和递归的函数);还有,即使是最简单的虚函数调用,编译器的内联处理程序对它也爱莫能助。(这一点也不奇怪。virtual的意思是"等到运行时再决定调用哪个函数",inline的意思是"在编译期间将调用之处用被调函数来代替",如果编译器甚至还不知道哪个函数将被调用,当然就不能责怪它拒绝生成内联调用了)。以上可以归结为:一个给定的内联函数是否真的被内联取决于所用的编译器的具体实现。

假设写了某个函数f并声明为inline,如果出于什么原因,编译器决定不对它内联,那将会发生些什么呢?最明显的一个回答是将f作为一个非内联函数来处理:为f生成代码时就象它是一个普通的"外联"函数一样, 对f的调用也象对普通函数调用那样进行。

条款33: 明智地使用内联

时间: 2024-10-04 17:16:41

条款33: 明智地使用内联的相关文章

内联函数详解

什么是内联性和外联函数 类的成员函数可以分为内联函数和外联函数.内联函数是指那些定义在类体内的成员函数,即该函数的函数体放在类体内.而说明在类体内,定义在类体外的成员函数叫外联函数.外联函数的函数体在类的实现部分. 内联函数在调用时不是像一般的函数那样要转去执行被调用函数的函数体,执行完成后再转回调用函数中,执行其后语句,而是在调用函数处用内联函数体的代码来替换,这样将会节省调用开销,提高运行速度. 内联函数与前面讲过的带参数的宏定义进行一下比较,它们的代码效率是一样的,但是内联函数要优于宏定义

HTML5进阶段内联标签汇总(小篇)

HTML5进阶段内联标签汇总(小篇) 内联元素,与别人公用一行,但是设置宽高无效.其特点: ①和其他元素都在一行上: ②高,行高及外边距和内边距不可改变: ③宽度就是它的文字或图片的宽度,不可改变 ④内联元素只能容纳文本或者其他内联元素 代码如下: 1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>

Effective C++:条款33:避免遮掩继承而来的名称

(一) 下面这段代码: int x; void someFunc() { double x; //local variable std::cin>>x; //read a new value to local x } 这个指涉的是local变量x,而不是global变量x,因为内存作用域会的名称遮掩外围作用域的名称.当编译器处于someFunc的作用域内并遭遇名称x时,他在local作用域内查找是否有什么东西带着这个名称.如果找到就不再找其他作用域.someFunc的x是double类型而gl

非内联css样式获取方法

css样式分为内联样式.内部样式和外部样式,然而object.style.xxx只能够获取内联样式的属性值,内部样式和外部样式的css样式获取不到 js获取方法使用document.defaultView.getComputedStyle().currentStyle() 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 &

【转】ios内联函数 inline

ios内联函数 inline 缘由 由于在学习使用UIScrollVew开发的过程中,碰到下面这个属性(设置内边距): @property(nonatomic) UIEdgeInsets scrollIndicatorInsets; // default is UIEdgeInsetsZero. adjust indicators inside 1 光看UIEdgeInsets这个类型,一时还不知道它的具体内部结构是怎么样的,于是继续点进去发现它的定义如下: typedef struct UIE

SqlSever基础 where inner join 内联表,两个表按照指定条件合作显示内容

镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ 1 code 1 --创建一个数据库 2 create database helloworld1 3 4 5 --用helloworld1这个数据库 6 use helloworld1 7 8 --创建一个表格teacher 9 create table Teacher 10 ( 11 Id in

《C++编程思想》第八章 内 联 函 数 (知识点+习题+解答)

一.相关知识点 任何在类中定义的函数自动地成为内联函数,但也可以使用inline关键字放在类外定义的函数前面使之成为内联函数.但为了使之有效,必须使函数体和声明结合在一起,否则,编译器将它作为普通函数对待.因此 inline int PlusOne(int x); 没有任何效果,仅仅只是声明函数(这不一定能够在稍后某个时候得到一个内联定义).成功的方法如下: inline int PlusOne(int x) { return ++x ;} 在头文件里,内联函数默认为内部连接--即它是 stat

深入理解java虚拟机(十四)正确利用 JVM 的方法内联

在IntelliJ IDEA里面Ctrl+Alt+M用来拆分方法.选中一段代码,敲下这个组合,非常简单.Eclipse也用类似的快捷键,使用 Alt+Shift+M.我讨厌长的方法,提起这个下面这个方法我就觉得太长了: public void processOnEndOfDay(Contract c) { if (DateUtils.addDays(c.getCreated(), 7).before(new Date())) { priorityHandling(c, OUTDATED_FEE)

CSS3与页面布局学习总结(二)——Box Model、边距折叠、内联与块标签、CSSReset

一.盒子模型(Box Model) 盒子模型也有人称为框模型,HTML中的多数元素都会在浏览器中生成一个矩形的区域,每个区域包含四个组成部分,从外向内依次是:外边距(Margin).边框(Border).内边距(Padding)和内容(Content),其实盒子模型有两种,分别是 ie 盒子模型和标准 w3c 盒子模型,加上了doctype声明,让所有浏览器都会采用标准 w3c 盒子模型去解释你的盒子.当设置一个元素的样式如下: <!DOCTYPE html> <html> <