学科分类
目录
C语言

带参数的宏定义

不带参数的宏定义只能完成一些简单的替换数值操作,如果希望程序在完成替换的过程中,能够进行一些更加灵活的操作,例如,根据不同的半径计算圆的周长,这时可以使用带参数的宏定义。带参数的宏定义语法格式如下:

#define 标识符(参数1,参数2,…) 字符串

和不带参数的宏定义格式相比,带参数的宏定义语法格式中多了一个包含若干参数的括号,括号中的多个参数之间使用逗号分隔。对于带参数的宏定义来说,同样需要使用字符串替换宏名,使用实参替换形参。

接下来通过一个计算圆周长的案例演示带参数宏定义的使用,如例1所示。

例1 definePara.c

 1  #include <stdio.h>
 2  #define PI 3.14                //定义宏PI
 3  #define COMP_CIR(x) 2 * PI * x        //定义带参数的宏COMP_CIR
 4  int main() 
 5  {
 6    double r = 1.0;
 7    printf("2 * pi * r = %f\n", COMP_CIR(r)); //引用宏COMP_CIR
 8    return 0;
 9  }

例1运行结果如图1所示。

图1 例1运行结果

在例1中,第2行代码定义了不带参数的宏PI;第3行代码定义了带参数x的宏COMP_CIR,用于表示半径为x的圆的周长;第6行代码定义了一个double类型的变量r,其值为1.0;第7行代码引用宏COMP_CIR,并将变量r作为其参数,最终输出半径为r的圆的周长。由图1可知,半径为1.0的圆的周长为6.28。

在例1中,第7行代码在预处理时,由于宏定义COMP_CIR(x)嵌套了宏定义PI,程序首先会将宏定义PI替换成3.14,然后将参数x替换成半径r,替换后的代码如下所示:

printf("2 * pi * r = %f\n", 2*3.14*r);

通过上面的例子,可能会让有的读者觉得,带参宏定义和带参函数有时可以实现同样的功能,但两者却有着本质上的不同,具体如表1所示。

表1 带参数的宏定义与带参数的函数的区别

基本操作 带参数的宏定义 带参数的函数
处理时间 预处理 编译、运行时
参数类型 需定义参数类型
参数传递 不分配内存,无值传递的问题 分配内存,将实参值带入形参
运行速度 相对较慢,因为函数的调用会涉及到内存分配、参数传递、压栈、出栈等操作

带参宏定义非常灵活,而且宏定义在程序预处理的时候就执行了,相比于函数,宏定义的“开销”要小一些,因此很多程序员喜欢使用宏定义代替一些函数的功能。

但是,在使用带参数的宏定义时,务必要注意参数替换问题,例如,定义带参宏定义ABS,用于计算参数的绝对值,示例代码如下所示:

#define ABS(x) ((x) >= 0 ? (x) : -(x)) //定义宏计算x的绝对值

上面代码定义了带参数的宏ABS(x),用于计算参数x的绝对值,宏体是一个条件表达式,如果参数x>0,就返回x本身作为其绝对值,如果x>0不成立,就取-x作为其绝对值。

该宏定义本身没有任何问题,例如定义double x = 12;传入参数x,计算结果为12。但是,当传入++x时,计算结果会出现错误,具体如例2所示。

例2 abs.c

 1  #include <stdio.h>
 2  #define ABS(x) ((x) >= 0 ? (x) : -(x)) //定义宏计算x的绝对值
 3  double compAbs(double x)        //定义函数计算x的绝对值
 4  {
 5    return x >= 0 ? x : -x;
 6  }
 7  int main() 
 8  {
 9    double x = 12, y = 12;
 10   printf("ABS(++x) = %f\n", ABS(++x));    //宏ABS计算++x的绝对值
 11   printf("compAbs(++y) = %f\n", compAbs(++y));//compAbs()计算++y绝对值
 12   return 0;
 13 }

例2运行结果如图2所示。

图2 例2运行结果

在例2中,第2行代码定义宏ABS;第3~6行代码定义compAbs()函数;宏定义ABS和函数comAbs()都用于计算绝对值。第10~11行代码,分别调用宏ABS和compAbs()函数计算++x和++y的绝对值。从图2中可以看出,两者计算出的结果不一样。显然compAbs()函数计算出的结果13才是正确的。这是因为宏ABS在替换时,首先会将参数进行替换,替换后的表达式如下所示:

((++x) >= 0 ? (++x) : -(++x)));

在上述代码中,当x等于12时,首先会被自增为13,判断13>=0成立,则取(++x)作为整个表达的结果,再次执行++x操作,x的结果变为14,将14返回作为整个表达式的结果,造成计算结果错误。因此,在使用宏定义代替函数时,一定要注意这样的参数替换问题,避免程序出现错误。

点击此处
隐藏目录