原文地址:http://www.programmerinterview.com/index.php/c-cplusplus/inline-vs-macro/
这个问题在苹果公司(Apple)和直觉(Intuit)公司面试时都有问到。
内联函数和宏定义的主要区别是不同的处理方式。内联函数由编译器处理,而宏定义则通过C++预处理器展开。这个区别也产生了其他的不同,通过例子可以很好的说明。
C++预处理器通过简单的文本替换来实现宏。假设我们定义了下面的宏:
#define SUM(a,b) (a+b)
当预处理器在代码中遇到SUM(first, last)时,会替换为(first + last)。什么时候会想用宏呢?一般对于简单的函数,为了避免函数调用的额外开销,就会使用宏。记住函数调用会产生开销。
内联函数则直接由编译器解析,而不是预处理器。内联函数和一般的函数很相似。下面是SUM宏的内联函数实现:
// note the use of the 'inline' keyword
inline int sum(int a, int b)
{
return (a+b);
}
内联函数和一般函数的区别是,每当编译器遇到一个内联函数的调用时,就
写入一个该函数的已编译过的副本。而对于一般的函数,则会产生一个正常的函数调用。
内联函数和宏都是为了消除函数调用的开销。于此同时,代码长度都会增加。记住,内联函数和一般函数很相似,而宏则是文本替换。
事实上,宏在做文本替换时很容易产生bug。假设有下面的定义:
#define DOUBLE(X) X*X
int y = 3;
int j = DOUBLE(++y);
如果你认为
j 将会赋值为4的平方(16),那么恭喜你错了。事实上,文本替换以后,DOUBLE(++y)就扩展为 ++y * ++y,等价于 4 * 5,结果是20。而DOUBLE用内联函数实现时则不会产生这个错误。内联函数只计算一次参数值,因此任何参数计算的副作用只会发生一次。
宏的另一个问题是关于语句结合。假设我们定义的宏有两个语句,然后将其用于 if 语句。如果没有使用大括号,则会像下面这样:
#define ADD_TWO(x,y) x += 2; y +=2
bool flag = true;
int j = 5, k = 7;
if(flag)
ADD_TWO(j,k);
你很可能会任务宏扩展应该是这样的:
if(flag)
{
j +=2;
k +=2;
}
但是实际上if语句只和宏定义的第一个语句结合。实际扩展为:
if(flag)
{
j +=2;
}
k +=2;
如果使用的是内联函数,就不会发生上面的问题了。这是因为内联函数是作为一个单独的语句,整个函数都会和if语句结合。
Debug宏也比较困难。因为预处理器会对宏做文本替换,而这在源代码中是看不出来的。综上所述,相比宏使用内联函数是一个不错的选择。