网页功能: 加入收藏 设为首页 网站搜索  
C++基本功和 Design Pattern系列(8) inline
发表日期:2007-03-28作者:[转贴] 出处:  

======================================================
大家请把我的文章当参考,详细内容 还请参照 权威书
籍如果文中有错误和遗漏, 请指出,Aear会尽力更正,
谢谢!
Aear Blog: http://blog.sina.com.cn/u/1261532101
======================================================

今天讲的是inline. 其实大家都知道,inline并不是c++独有的特性。其实Aear的个人观点,inline根本就不应该是语言标准的一部分。因为inline的具体实现,跟compiler有很大的关系,把inline说成compiler的一个开关更合适一些。今天我们就说下在什么情况下可以使用inline, 使用inline的好处和坏处。

================= Inline能做什么 =================

关于inline能做什么,什么原理,相信很多人都知道。Aear再在这里重复一下:

1. inline能够去掉function call的overhead
2. inline能够帮助函数调用时候常量参数进行优化

举个例子来说明一:

void function(void)
{

}

function();

在调用function()前,一般会进行下面的操作(根据操作系统和compiler来决定,并不一定按照这个顺序):
    保存IP FP SP等寄存器的值(压栈)
    把参数压栈
    建立新的 IP FP SP等以便进行函数调用
    函数有可能还需要保存一些寄存器数据到内存。

在完成function()调用后,也会进行一系列的操作:
    如果有返回值,一般在一个寄存器中,需要进行一系列的处理工作
    恢复IP FP SP等保存的寄存器值。

整个过程大约需要花费20-150个CPU clock cycle.具体要根据参数的多少,还有函数的具体实现来决定。使用inline function,可以去掉这些函数调用前和调用后的工作,从而节省CPU clock cycle,提高程序的运行效率。

关于2的情况,例子如下:
    float test = cos(0);

如果cos不是inline,compiler有可能会生成cos()的调用代码,计算cos(0),然后返回给test.如果cos被inline了,由于cos(0) == 1,所以经过优化的代码可是直接生成test = 1.

================= Inline 坏处 =================

Aear个人认为,inline只在特定的情况下起到正面的作用,在大部分情况下,起到负面的作用,也就是说,坏处多过好处。使用inline的缺点包括:

1. 不容易debug,并不是所有的debugger都支持在inline function中设置断点,不过幸运的是,VS .net支持。

2. 很容易增加代码的长度,在很多情况下,代码长度的增加直接导致了代码执行速度的减慢,特别是在循环中,因为整个循环的长度超过了cache的容量,从而使得cache miss的几率增大

3. 使得编译的时间过长。如果一个inline function被更改,所有调用这个程序的代码都要重新编译。对于一般的游戏代码,整个编译时间可能会有1,2个小时。

4. 暴露了代码实现细节。由于inline function必须在header file中定义,所以导致使用者能够看到你的代码实现细节。

Inline并不是一个好东西,也不是一个万能药,在很多时候,它会给你带来无穷无尽的麻烦。所以在inline的时候,最好慎重慎重。

================= 如何使用 Inline =================

下面给出几种inline的用法。由于个人的代码结构,平台,实现细节的不同,请参考相关资料自行决定.

========= Platform Inline =========
首先要指出的是,inline并不是一条命令,而是对compiler的建议。compiler会具体分析你的代码,如果合适inline,才会进行inline的工作。在VS .net下,一共有3个关于inline的定义:

inline
__inline (__inline__ for GCC)
__forceinline

inline和__inline相同,只有compiler认为inline合适,才会进行。__forceinline是强制compiler进行inline. 比如:

__forceinline void f(void);

如果你使用了inline或者__inline, 并且打开了编译器的 /Ob开关,那么compiler就会告诉你一个function是不是被真正的inline了。

========= Macro Inline =========

使用一个macro来控制inline,我们可以做如下定义:

#ifdef _DEBUG
#define COND_INLINE
#else
#define COND_INLINE inline
#endif

// inline function declaration
COND_INLINE function();

这样我们在debug模式下,就不会有inline带来的烦恼了。只有在release version,编译器才会进行真正的inline.


========= Inline Condition =========

一般来讲,根据程序员主观感觉inline得到的很有可能就是负面的效果。下面的一些情况,能够帮大家决定是否inline一个函数:

1. 使用profiler分析的结果告诉你需要inline一个function。这个是最有把握的。windows下比较流行的profiler是vTune

2. class的属性访问函数(Accessor Methods)。一般来讲,这些是可以inline的,而且很多compiler都会帮你自动inline这些函数。

3. 小函数。这个需要举个例子说明,代码如下:

int Cal(int x, int y, int z)
{
    return x+y-z;
}

我们可以看到 Cal的代码很少,就是计算 x+y-Z,最多也就3,4条汇编代码。但是如果不inline, Cal函数的调用和返回过程所产生的代码,都比cal实际运行的代码多。因此Cal最好inline,通过消除Cal的调用和返回的代码,可以减少可执行程序的大小,同时加快运行的速度。

因此,一般来讲,5行内逻辑结构简单的代码,可以比较放心的inline,大过5行的代码,就需要仔细的斟酌了。

================= 不能Inline的情况 =================

1. 包含Static Member的function. 很多compiler不能inline有static member的function.或者即使inline了,也会生成错误的代码(把static当成local处理)。所以最好先测试下compiler支持不支持static inline.测试代码可以这么写:

inline void f(void)
{
    static int k = 1;
    k++;
    std::cout<<k<<endl;
}

f();
f();

2. virtual member function.  Virtual Member Function在很多情况下是不能被inline的(根据compiler而定),因为具体virtual的哪个版本被调用,要在运行时候才能决定。不过我们可以通过创建一个新的可以inline的non-virtual member function,来提高运行速度。


================= 结论 =================

总的来说,inline的坏处多过好处,请大家inline的时候,慎重慎重再慎重,并不是所有的函数都适合inline的。


我来说两句】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 C++基本功和 Design Pattern系列(8) inline
本类热点文章
  智能指针的标准之争:Boost vs. Loki
  创建模块化游戏 I(翻译)(Creating M..
  C++基本功和 Design Pattern系列(6) pu..
  C++基本功和 Design Pattern系列(11) E..
  网络在线游戏开发心得(服务器端、Java)
  用3D方法实现2D斜视角地图
  C++基本功和 Design Pattern系列(8) in..
  物品管理系统
  C++的学习感想
  C++基本功和 Design Pattern系列(10) B..
  解析boost
  C++基本功和 Design Pattern系列(9) vi..
最新分类信息我要发布 
最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放  
Copyright ©2003-2024 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.00424