内联函数与宏

来源:互联网 发布:淘宝不支持评价的商品 编辑:程序博客网 时间:2024/06/05 06:43

(1)

宏是由预处理器对宏进行替代,而内联函数是通过编译器控制来实现展开。

(1.1)预处理器不能进行类型安全检查,或者进行自动类型转换。

(1.2)对于任何内联函数,编译器在符号表里放入函数的声明(包括名字、参数类型、返回值类型)。

如果编译器没有发现内联函数存在错误,那么该函数的代码也被放入符号表里。

在调用一个内联函数时,编译器首先检查调用是否正确

(进行类型安全检查,或者进行自动类型转换,当然对所有的函数都一样)。

如果正确,内联函数的代码就会直接替换函数调用,于是省去了函数调用的开销

 

(2)

内联函数是真正的函数,只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销。

(3)

内联函数不会像宏那样带来副作用。

(4)

内联函数提高了速度或效率,但增加了代码规模

(5)

内联函数必须是和函数体申明在一起,才有效。

(6)

函数体内不能有循环语句和switch语句。

(7)

内联函数不能过大,过大是编译器将放弃内联方式,改用普通方式调用此函数。即使使用了inline关键字。

(8)

使用宏代码最大的缺点是容易出错,预处理器在复制宏代码时常常产生意想不到的边际效应。

对于c++而言,使用宏代码还有另一种缺点:无法操作类的私有数据成员。

(9)

定义在类内的函数可能会被定义为内联函数。

(10)

内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。以下情况不宜使用内联:
(1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
(2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构函数可能会隐藏一些行为,如“偷偷地”执行了基类或成员对象的构造函数和析构函数。所以不要随便地将构造函数和析构函数的定义体放在类声明中。
一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明了inline不应该出现在函数的声明中)。

(11)

对象的构造函数和析构函数最好不要定义成内联函数。

(12)

内联机制既可用于全局函数也可成员函数

(13)

在debug 版本中,内联函数还没有展开,可以调试。

宏不能调试。

///////////////////////////////////////

1、内联函数与宏一样是进行代码展开的,但内联函数可以调试,可以进行参数、返回值的类型检查和自动类型转换,并且内联函数还有宏无法做到的功能:访问类私有成员。为什么内联函数展开后还能调试?这里的调试不是指展开后的内联函数。内联函数之所以可以调试,是因为在调试(Debug)模式下,内联函数没有进行真正的代码展开;只有在发行(Release)版中,编译器才会真正的内联,进行代码展开。VS2005可以设置内联函数是否展开,在工程属性的配置属性中,C/C++ -> 优化 -> 内联函数展开。

2、C++中的内联函数既具有宏代码的效率,又有类型检查等优点。因此,在C++中,应尽量用内联函数代替宏(除了assert断言宏,原因在于断言要求只在debug版中起效,而release版中不能受影响)。在boost库中可以看到很多内联的全局函数和成员函数。

3、函数内联后,编译器可以通过上下文相关的优化技术对展开的代码进行深入优化。这种优化在普通函数中无法进行,因为一旦进入函数体之后,也就脱离了调用环境的上下文。

4、内联会进行代码展开,造成代码膨胀,仅仅省去了参数压栈,跳转,退栈和返回的操作。若代码逻辑比较复杂,或存在循环等,则不适宜使用内联函数。

另:inline是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。所以,inline必须与函数定义放在一起才能使函数内联,仅放在函数声明中不起作用。

转自:http://www.zxbc.cn/kfyy/0819565.html

 

    (一)内联函数和宏的区别在于,宏是由预处理器对宏进行替代,而内联函数是

  通过编译器控制来实现的。而且内联函数是真正的函数,只是在需要用到的时

  候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开

  销。你可以象调用函数一样来调用内联函数,而不必担心会产生于处理宏的一

  些问题。

  我们可以用inline来定义内联函数,不过,任何在类的说明部分定义的函

  数都会被自动的认为是内联函数。

  (二)

  内联函数必须是和函数体申明在一起,才有效。

  像这样的申明inlinetablefunction(inti)是没有效果的,编译器只是把函数作为普通的函

  数申明,我们必须定义函数体。

  inlinetablefunction(inti){returnii};

  这样我们才算定义了一个内联函数。我们可以把它作为一般的函数一样调

  用。但是执行速度确比一般函数的执行速度要快。但内联函数不能过大,过大是编译器将放弃内联方式,改用普通方式调用此函数。

  (三)

  函数内联

  用内联取代宏代码

  ----------------

  c++语言支持函数内联,其目的是为了提高函数的执行效率(速度)。

  在c程序中,可以用宏代码提高执行效率。宏代码本身不是函数,但使用起来象函数。

  预处理器用复制宏代码的方式代替函数调用,省去了参数压栈、生成汇编语言的call调用、

  返回参数、执行return等过程,从而提高了速度。

  使用宏代码最大的缺点是容易出错,预处理器在复制宏代码时常常产生意想不到的边际效应。

  对于c++而言,使用宏代码还有另一种缺点:无法操作类的私有数据成员。

  让我们看看c++的"函数内联"是如何工作的。

  对于任何内联函数,编译器在符号表里放入函数的声明(包括名字、参数类型、返回值类型)。

  如果编译器没有发现内联函数存在错误,那么该函数的代码也被放入符号表里。

  在调用一个内联函数时,编译器首先检查调用是否正确

  (进行类型安全检查,或者进行自动类型转换,当然对所有的函数都一样)。

  如果正确,内联函数的代码就会直接替换函数调用,于是省去了函数调用的开销。

  这个过程与预处理有显著的不同,因为预处理器不能进行类型安全检查,或者进行自动类型转换。

  假如内联函数是成员函数,对象的地址(this)会被放在合适的地方,这也是预处理器办不到的。

  c++语言的函数内联机制既具备宏代码的效率,又增加了安全性,而且可以自由操作类的数据成员。

  所以在c++程序中,应该用内联函数取代所有宏代码,"断言assert"恐怕是唯一的例外。

  assert是仅在debug版本起作用的宏,它用于检查"不应该"发生的情况。

  为了不在程序的debug版本和release版本引起差别,assert不应该产生任何副作用。

  如果assert是函数,由于函数调用会引起内存、代码的变动,那么将导致debug版本与release版本存在差异。

  所以assert不是函数,而是宏。函数内联

  用内联取代宏代码

  ----------------

  c++语言支持函数内联,其目的是为了提高函数的执行效率(速度)。

  在c程序中,可以用宏代码提高执行效率。宏代码本身不是函数,但使用起来象函数。

  预处理器用复制宏代码的方式代替函数调用,省去了参数压栈、生成汇编语言的call调用、

  返回参数、执行return等过程,从而提高了速度。

  使用宏代码最大的缺点是容易出错,预处理器在复制宏代码时常常产生意想不到的边际效应。

  对于c++而言,使用宏代码还有另一种缺点:无法操作类的私有数据成员。

  让我们看看c++的"函数内联"是如何工作的。

  对于任何内联函数,编译器在符号表里放入函数的声明(包括名字、参数类型、返回值类型)。

  如果编译器没有发现内联函数存在错误,那么该函数的代码也被放入符号表里。

  在调用一个内联函数时,编译器首先检查调用是否正确

  (进行类型安全检查,或者进行自动类型转换,当然对所有的函数都一样)。

  如果正确,内联函数的代码就会直接替换函数调用,于是省去了函数调用的开销。

  这个过程与预处理有显著的不同,因为预处理器不能进行类型安全检查,或者进行自动类型转换。

  假如内联函数是成员函数,对象的地址(this)会被放在合适的地方,这也是预处理器办不到的。

  c++语言的函数内联机制既具备宏代码的效率,又增加了安全性,而且可以自由操作类的数据成员。

  所以在c++程序中,应该用内联函数取代所有宏代码,"断言assert"恐怕是唯一的例外。

  assert是仅在debug版本起作用的宏,它用于检查"不应该"发生的情况。

  为了不在程序的debug版本和release版本引起差别,assert不应该产生任何副作用。

  如果assert是函数,由于函数调用会引起内存、代码的变动,那么将导致debug版本与release版本存在差异。

  所以assert不是函数,而是宏。

 

慎用内联
内联能提高函数的执行效率,为什么不把所有的函数都定义成内联函数?
如果所有的函数都是内联函数,还用得着“内联”这个关键字吗?
内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。以下情况不宜使用内联:
(1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
(2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构函数可能会隐藏一些行为,如“偷偷地”执行了基类或成员对象的构造函数和析构函数。所以不要随便地将构造函数和析构函数的定义体放在类声明中。
一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明了inline不应该出现在函数的声明中)。

原创粉丝点击