- 我们编写一个求一个数平方的运算,
#define宏定义实现如下:
#define SQUARE1(X) X*X
inline内联函数实现如下:
inline int SQUARE2(int X){return X*X;}
END
步骤2——定义所需变量
- 1
首先定义所需变量:
int a=5,b=5;
int s1=0,s2=0;
定义a和b值相同,其中a代入#define测试,b代入inline测试;
s1存储#define结果,s2存储inline结果。
END
步骤3——测试#define和inline
- 1
测试1:编写如下代码:
s1 = SQUARE1(a);
cout<<"s1= "<<s1<<endl;
s2 = SQUARE2(b);
cout<<"s2= "<<s2<<endl;
结果输出:
s1= 25
s2= 25
可以看到两者输出结果相同,分析:
s1 = SQUARE1(a);等同于
s1 = a*a;
所以s1等于a的平方25;
s2 = SQUARE2(b);等同于
先进行SQYARE2()函数调用,b(5)作为实参传递,函数返回5*5的值,然后再把该值赋给s2,所以s2同样等于25
- 2
测试2:编写如下代码:
s1 = SQUARE1(a+b);
cout<<"s1= "<<s1<<endl;
s2 = SQUARE2(a+b);
cout<<"s2= "<<s2<<endl;
结果输出:
s1= 35
s2= 100
可以看到两者输出结果不相同,分析:
s1 = SQUARE1(a+b);等同于
s1 = a+b*a+b;
可以看到#define仅仅进行单纯的替换,那么由于运算符存在优先级,得到
s1 = 5+25+5=35;
s2 = SQUARE2(a+b);等同于
先进行SQYARE2()函数调用,a+b的结果10作为实参传递,函数返回10*10的值,然后再把该值赋给s2,所以s2同样等于100。
这里涉及到程序顺序点的知识,对应这里就是#define只进行简单替换,整个SQUARE1(a+b)后面是顺序点,而对于inline定义的SQUARE2(a+b)来说,存在两个顺序点,第一个在a+b后,第二个在整个SQUARE2(a+b)后,也就是说程序会先进行a+b的运算(顺序点1),把得到的结果再参与SQUARE2()内部代码运算(顺序点2)。
- 3
可能有人会说,把#define坐入如下改进就可以解决问题了:
#define SQUARE1(X) ((X)*(X))
的确这样上面的问题就解决了,但会不会还存在其他问题呢?
看下面的测试3:
- 4
测试3:编写如下代码:
s1 = SQUARE1(a++);
cout<<"s1= "<<s1<<endl;
cout<<"a = "<<a<<endl;
s2 = SQUARE2(b++);
cout<<"s2= "<<s2<<endl;
cout<<"b = "<<b<<endl;
结果输出:
s1= 25
a = 7
s2= 25
b = 6
可以看到两者输出结果不尽相同,分析:
s1 = SQUARE1(a++);等同于
s1 = a++*a++;由于后缀++是先使用后递增,所以
s1 = 5*5 = 25
然后a两次递增得到a=7
s2 = SQUARE2(b++);等同于
先进行SQUARE2()函数调用,同样由于后缀++先使用后递增的原则,b的初始值5作为实参传递,函数返回5*5的值,然后再把该值赋给s2,所以s2等于25;
然后b++得到b=6
参照前面介绍的顺序点的知识,就会发现在这种情况下,#define会将参数递增两次,而inline则将参数递增一次,即使进行第三步中的改进此问题依然存在,详见下面实测截图
- 5
实测结果如下图:
#define SQUARE1(X) X*X
- 6
#define SQUARE1(X) ((X)*(X))
可以看到测试2的问题得到解决,但测试3问题依然存在
END
注意事项
- 如果使用C语言的宏执行类似函数的操作,应考虑将它们转换为C++内联函数