您的位置:首页 > 其它

函数、宏、内联函数

2010-08-18 11:54 183 查看
函数、宏、内联函数

第一部分:宏

为什么要使用宏呢?

因为函数的调用必须要将程序执行的顺序转移到函数所存放在内存中的某个地址,将函数的程序内容执行完后,再返回到转去执行该函数前的地方。这种转移操作要求在转去执行前要保存现场并记忆执行的地址,转回后要恢复现场,并按原来保存地址继续执行。因此,函数调用要有一定的时间和空间方面的开销,于是将影响其效率。

【调用函数的开销】大致可分两个部分:传递参数的开销和保存当前程序上下文信息所花费的开销。
对于传递参数的开销而言,传递的参数越多开销就越大;
对于保存当前程序上下文所花费的开销而言,函数越复杂需要花费的开销就越大。

而宏只是在预处理的地方把代码展开,不需要额外的空间和时间方面的开销,所以调用一个宏比调用一个函数更有效率。

宏在某种程度上可以代替函数,避免函数调用带来的开销。定义完宏之后,由预处理器对宏进行替代。
对于宏而言,虽然避免了函数调用带来的开销,但是增加了内存的开销。因为在每个应用宏的地方宏都会展开。
另外,宏易读性比较差,容易出现问题。
例如:
#define MAX(a,b) ((a) < (b) ? (b):(a))
void main()
{
int a = 10;
int b = 11;
int c = 0;
c = MAX(a++,b++);
cout << c << endl;
cin >> c;
}
我们会发现c的结果为12,因为宏展开之后变为:((a++) < (b++) ? (b++) : (a++))并不是我们预想中的结果。故一般来讲最好不使用宏。

宏的不尽人意的地方还有:
1、宏不能访问对象的私有成员。
2、宏的定义很容易产生二意性。

例如:

#define square(x) (x*x)

我们用一个数字去调用它,square(5),这样看上去没有什么错误,结果返回25,是正确的,但是如果我们用squre (5+5)去调用的话,我们期望的结果是100,而宏的调用结果是(5+5*5+5),结果是35,这显然不是我们要得到的结果。避免这些错误的方法,一是给宏的参数都加上括号。

#define square(x) ((x)*(x))

第二部分:内联函数

从上面的阐述,可以看到宏有一些难以避免的问题,怎么解决呢?

【内联函数】是代码被插入到调用者代码处的函数。如同 #define 宏,内联函数通过避免被调用的开销来提高执行效率,尤其是它能够通过调用(“过程化集成”)被编译器优化。

内联函数和宏很类似,而区别在于:

宏是由预处理器对宏进行替代,而内联函数是通过编译器控制来实现的。而且内联函数是真正的函数,只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销。你可以象调用函数一样来调用内联函数,而不必担心会产生于处理宏的一些问题。

内联函数是避免函数调用开销的另一种方法,与宏类似,但与宏相比拥有参数类型检查的优点。

声明内联函数看上去和普通函数非常相似:

void f(int i, char c);

当你定义一个内联函数时,在函数定义前加上 inline 关键字,并且将定义放入头文件:

inline void f(int i, char c)

{

// ...

}

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

像这样的申明inline function(int i)是没有效果的,编译器只是把函数作为普通的函数申明,我们必须定义函数体。

inline int function(int i) {return i*i;}

这样我们才算定义了一个内联函数。我们可以把它作为一般的函数一样调用。但是执行速度确比一般函数的执行速度要快。

当然,内联函数也有一定的局限性。虽然效率要快,但不是所有的函数都可以设置为内联函数。若函数体过于复杂,编译工具会自动取消函数的内联特性,将函数作为普通函数来对待。这样,内联函数就和普通函数执行效率一样了。

有上面的两者的特性,我们可以用内联函数完全取代预处理宏。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: