#define TABLE_COMP(x)((x)>0?(x):0)
这是一个宏定义,为什么要用宏呢?
因为函数的调用必须将程序执行的顺序转移到函数所存放在内存中的某个地址,将函数的程序内容执行完后,再返回到执行该函数所存放在内存中的某个地址,将函数的程序内容执行完后,再返回到执行该函数前的地方,这种转移操作的要求在转去执行前要保存现场,并记忆执行的地址,转会后要恢复现场,并将原来保存地址继续执行,因此,函数调用需要有一定的时间和空间方面的开销,于是将影响其效率,而宏只是在预处理的地方把代码展开,不需要额外的空间和时间的开销,所以调用一个宏比调用一个函数更有效率
但是宏也有很多不尽人意的地方:
1、宏不能访问对象的私有成员
2、宏定义容易产生二义性
例如:
#define TABLE_MULTI(x) (x*x)
x=1时,宏返回结果与预期一致,当x=1+2时,宏执行的为1+2*1+2,与预期(1+2)*(1+2)的结果有偏差。可以通过如下改善这个问题。
#define TABLE_MULTI(x) ((x)*(x))
但是这样仍然存在问题,如TABLE_MULTI(a++)本意是(a+1)*(a+1),而实际是(a++)*(a++),如下面程序
#include <iostream>
#define A(x) ((x)*(x))
int func(int* x)
{
int sum;
std::cout << "x:" << *x << std::endl;
sum = ((*x)++)*((*x)++);
std::cout << "x:" << *x << std::endl;
return sum;
}
int main(int argc, const char * argv[]) {
// insert code here...
std::cout << "Hello, World!\n";
int a = 1;
int b = 1;
std::cout << A(a++) << " " << a << std::endl;
std::cout << func(&b) << " " << b << std::endl;
return 0;
}
使用Mac的XCode编译运行打印结果为:
Hello, World!
2 3
x:1
x:3
2 3
可见,不管是宏还是函数,都没有达到我们的预期结果4。下面我们就介绍一下内联函数来解决这个问题,实际上,用内联函数完全可以取代宏函数,二者的区别在于,1)宏是由预处理器对宏进行替换,而内联函数是通过编译器来实现的,内联函数是真正的函数,在用到的时候,像宏一样展开。2)内联函数取消了函数的参数压栈,减少了调用的开销,可以像函数一样调用内联函数,而不必担心会产生宏处理的一些问题。3)内联函数的返回类型可以指定,宏函数没有类型的概念,只在宏展开后,才由编译器检查类型。
#include <iostream>
#define A(x) ((x)*(x))
int func(int* x)
{
int sum;
std::cout << "func x:" << *x << std::endl;
sum = ((*x))*((*x));
std::cout << "func x:" << *x << std::endl;
return sum;
}
inline int add(int x)
{
int sum;
std::cout << "add y:" << x << std::endl;
sum = (x)*(x);
std::cout << "add y:" << x << std::endl;
return sum;
}
int main(int argc, const char * argv[]) {
// insert code here...
std::cout << "Hello, World!\n";
int a = 1;
int b = 1;
int c = 1;
std::cout << A(a++) << " " << a << std::endl;
std::cout << func(&b) << " " << b << std::endl;
std::cout << add(c++) << " " << c << std::endl;
return 0;
}
打印结果:
Hello, World!
2 3
func x:1
func x:1
1 1
add y:1
add y:1
1 2
内联函数缺点:
1、内联函数的函数体不宜过大。代码一般十几行。如果内联函数的函数体过大,一般的编译器会放弃内联方式,使用普通方式
2、内联是以代码膨胀为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。
3、内联函数的调用都是要复制代码,使程序的总代码量增大,消耗更多的内存空间
以下情况不适宜使用内联:
1、如果函数体内的代码比较长,使用内联导致内存消耗代价较高
2、如果函数体出现循环,执行函数体内代码的时间要不函数调用的开销大
3、类的构造函数和析构函数容易让人误解成使用内联更有效。
内联函数的使用注意以下几点:
1、内联函数的定义性声明应该出现在对该函数的第一次调用之前
2、内联函数首先是函数,函数的很多性质都是用于内联函数,如内联函数可以重载
3、在内联函数中不允许使用循环语句和switch结果,带有异常接口声明的函数也不能声明为内联函数。
const与宏常量的区别:
1、const常量有数据类型,而宏常量没有数据类型,编译器对前者进行类型安全检查,对后者只能进行字符串替换。
2、编译器对二者的调试:对const常量可以进行调试,在C++程序中只使用const常量而不使用宏常量,即const常量完全取代宏常量。