游戏开发论坛

 找回密码
 立即注册
搜索
查看: 10899|回复: 9

C++基本功和 Design Pattern系列(8) inline

[复制链接]

27

主题

179

帖子

259

积分

中级会员

Rank: 3Rank: 3

积分
259
发表于 2006-12-7 02:23:00 | 显示全部楼层 |阅读模式
======================================================
大家请把我的文章当参考,详细内容 还请参照 权威书
籍如果文中有错误和遗漏, 请指出,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的。






8

主题

716

帖子

716

积分

高级会员

Rank: 4

积分
716
发表于 2006-12-7 10:58:00 | 显示全部楼层

Re:C++基本功和 Design Pattern系列(8) inline

OO/design是大局观
inline之流属于微操范畴

微操所需要存在的场合是开局,以及兵力相当时的交战,目的是逐步拉开与对方的优势差距
大局观是整体和全局,是规模效应,一旦形成,可以一定程度得忽略微操

浑然一体,自然天成

8

主题

553

帖子

560

积分

高级会员

Rank: 4

积分
560
发表于 2006-12-8 20:11:00 | 显示全部楼层

Re:C++基本功和 Design Pattern系列(8) inline

其实泛泛而谈inline没有什么意思,一切都还是要看具体的情况。
马马,公司以前的driver,有一个函数inline了后,performance在vista上提高了进20%,这是我第一次被inline震惊。

6

主题

95

帖子

103

积分

注册会员

Rank: 2

积分
103
发表于 2006-12-9 17:22:00 | 显示全部楼层

Re:C++基本功和 Design Pattern系列(8) inline

我现在对inline的想法就是:希望只写.h文件时,避免连接错误。其实template用多了,就被迫inline了。

35

主题

370

帖子

376

积分

中级会员

Rank: 3Rank: 3

积分
376
发表于 2006-12-16 13:03:00 | 显示全部楼层

Re:C++基本功和 Design Pattern系列(8) inline

我们要用科学的观点来分析问题,用实践的态度来对待问题。不能不讨论,也不能不实验~

             调用开销应该这样算: 调用开销= (函数调用时间/函数体执行时间)*调用次数(频率),确切的说这个是代码效率计算。
             另外:以前我看了一本〈高质量C++编程〉里面说inline可以放在定义文件里,在定义函数的时候写上inline,而头文件可以不用写inline,因为调用函数的客户只关心函数接口,不关心它怎么实现。这个和上面说的后冲突,不知道大家实验过没。(我也还没去实验呵呵)
            

7

主题

438

帖子

438

积分

中级会员

Rank: 3Rank: 3

积分
438
发表于 2006-12-16 13:33:00 | 显示全部楼层

Re:C++基本功和 Design Pattern系列(8) inline

楼上说的那本书是渣,得到的结论是错的。

inline函数的声明和定义必须在一起,不然编译器忽略inline指令。

35

主题

370

帖子

376

积分

中级会员

Rank: 3Rank: 3

积分
376
发表于 2006-12-16 13:52:00 | 显示全部楼层

Re:C++基本功和 Design Pattern系列(8) inline

你实验过么。。

35

主题

370

帖子

376

积分

中级会员

Rank: 3Rank: 3

积分
376
发表于 2006-12-16 19:38:00 | 显示全部楼层

Re:C++基本功和 Design Pattern系列(8) inline

袄,想了想,从编译和连接的角度看应该是放在 头文件里

121

主题

2029

帖子

2034

积分

金牌会员

Rank: 6Rank: 6

积分
2034
QQ
发表于 2006-12-17 19:34:00 | 显示全部楼层

Re:C++基本功和 Design Pattern系列(8) inline

看什么《高质量》,要看就看传说中的《代码大全》 [em2]

35

主题

370

帖子

376

积分

中级会员

Rank: 3Rank: 3

积分
376
发表于 2006-12-17 21:27:00 | 显示全部楼层

Re:C++基本功和 Design Pattern系列(8) inline

哪是我以前看的,不过里面有些是对的。。。进步就是在不断改正错误~
代码大全好象不讲inline而且它不是针对个别语言的,是针对软件构架的
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-26 02:01

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表