宏与函数的一些优劣
一般宏用于执行简单的运算,例如:
#define MAX(a,b) ((a) > (b) ? (a) : (b))
这种情况下使用宏比使用函数要好,原因有两点:
1、调用函数要消耗系统一定的额外时间,执行额外的代码(保护处理器现场、数据压栈、函数返回、恢复处理器现场等操作)有可能这些额外的操作比这个小型的计算所消耗的时间更大,所以使用宏比使用函数在程序的规模和速度方面更胜一筹。
2、函数的参数必须声明为一种特定的类型,所以他们只能在特定的类型的表达式中使用,而使用上面的宏则任何只要可以使用“>”来比较大小的类型都可以使用该宏,换句话说,宏是与类型无关的。
与函数相比使用的宏的不利之处在于每次使用宏时,宏定义代码的拷贝都将插入到程序中。除非宏非常的短,否则使用宏将大幅度增加程序的长度
还有一些任务是无法使用函数来实现的,例如下面的宏实现的功能:
#define MALLOC(n,type) ((type *)malloc((n) * sizeof(type)))
我们观察一下这个宏的确切工作过程:
pi = MALLOC(25,int);
这句语句将会被预处理器替换成下面的语句:
pi = ((int *)malloc((n) * sizeof(int)));
而这个功能是无法使用函数来实现的。
带副作用的宏参数
所谓副作用就是在表达式求值中出现永久性效果,例如下面的表达式:
x+1;
可以重复出现几百次,它们每次执行的结果都是一样的,这个表达式不具备副作用。但是:
x++;
就具有副作用:它增加x的值,这个表达式在下一次执行时将会产生不同的结果,下面是一个带副作用的宏参数的例子:
#define MAX(a,b) ((a)>(b)?(a):(b))
......
x = 5;
y = 8;
z = MAX(x++,y++);
printf("x = %d, y = %d, z=%d/n", x,y,z);
函数将输出 x = 6, y = 10, z = 9;
可能初次看这个结果都无法理解,但是别忘了宏的处理方式,将这个宏替换成宏定义代码,这个结果就很明了了。
副作用并不仅限于改变变量的值,下面的表达式:
getchar();
注意这个表达式也是有副作用的,调用这个函数将“消耗”输入的一个字符,所以该函数的后续调用将得到不同的字符
#define宏的行为和真正的函数相比存在一些不同的地方,但是使用宏的语法和使用函数的语法是完全一样的,所以语言本身并不能帮助你区分两者,这就需要我们自己区分一个常见的约定是将宏的名字全部大写