C++中的const常量可以替换宏常量,那么是否有一个方法可以替代宏对代码块的替换呢?
有的,就是内联函数,在C++中推荐使用内联函数替代宏对代码的替换,在具体介绍内联函数之前我们可以看一个代码片段:
#include <stdio.h>
#define FUNC(a, b) ((a) < (b) ? (a) : (b))
int main(int argc, char *argv[])
{
int a = 1;
int b = 3;
int c = FUNC(++a, b);
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c);
return 0;
}
首先分析一下,宏代码块实现的功能是利用三目运算符返回较小值,按照我们分析知道++a后值应该为2,b不变仍旧为3,返回较小值2,所以c = 2;但是看一下输出:
a = 3;
b = 3;
c = 3;
输出和我们想的不一样,为什么?这就是宏的弊端,在预处理期作纯粹的文本替换,那么所以替换的代码就是;((++a) < b:? (++a) : b),返回结果自然就是3了。
所以我们需要一个可靠的方法进行代码扩展---内联函数
C++中使用inline关键字声明内联函数,并且在内联函数声明时inline关键字必须和函数定义结合在一起,否则编译器直接会忽略内敛请求。当编译器接受内联函数时就会进行内联编译,即直接将函数体插入到函数调用的地方,这样做的好处是没有函数调用时的额外开销(压栈、出栈、跳转)。内联函数具有普通函数的特征,参数检查和返回类型检查,这样也更说明了C++的严谨了。下面看一个内联函数的例子:
#include <stdio.h>
inline int func(int a, int b)
{
return a < b ? a : b;
}
int main(int argc, char *argv[])
{
int a = 1;
int b = 3;
int c = func(++a, b);
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c);
return 0;
}
输出为:
a = 2;
b = 3;
c = 2;
这样答案就和我们想的是一样的了。这就是内联函数相比于宏对代码块替换的好处了,不像宏那样直接替换,没有任何编译过程,因此不会出现副作用。
但是C++编译器不一定满足函数的内联请求,因为现在的编译器一般设置为默认选择,即不确定到底是否进行内联编译,需要人为设置编译器功能选项或者强行进行内联编译。
就不演示了,大家在使用内联函数时可以查看汇编代码了解编译器是否真正进行了内联编译。但是有一点值得提一下的是,现在先进的编译器能够进行编译优化,一些函数即使没有inline声明也可能被内联编译,即提供一些扩展语法让函数强制被内联编译,可以分为两种:
g++编译器使用__attribute__((always_inline))作为函数属性和MSVC编译器使用__forceinline作为函数属性可以强制被内联编译。
C++中inline内联编译是存在限制的:
1、不能存在任何形式的限制
2、不能存在过多的条件判断语句
3、函数体不能过于庞大
4、不能对函数进行取址操作
5、函数内联声明必须在调用语句之前
这些都是C++刚开发出来时进行的规定,但是由于技术的进步现代编译器对很多限制都不再是限制了。