目录
一、不带参数的宏定义
1.定义
在程序中,经常会定义一些常量,例如圆周率3.1415、“ABC”等。如果这些常量在程序中频繁使用,难免会出现书写错误的情况。为了避免程序书写错误,可以使用不带参数的宏定义来定义这些常量。
例如:#define PI 3.14159
解析:#define是用来标识一个宏定义,标识符PI是定义的宏名,3.14159是宏体,它可以是常量或表达式等。
一般情况下,宏定义需要放在源程序的开头,函数定义外,它的有效范围是从宏定义语句开始至源文件结束。一般宏名都是大写字母,方便与其他操作符区别。
使用宏定义PI就可以在随后的源代码中出现PI的位置替换为3.14159.
案例演示:
#include <stdio.h>
#define PI 3.141592
int main(){
int r;
scanf("%d",&r);
double area=PI*r*r;
double cicle=2*PI*r;
printf("半径为%d的圆面积:area=%lf 周长cicle=%lf\n",r,area,cicle);
}
运行结果:
2.#undef 指令取消宏定义
#undef指令用于取消宏定义,当使用#define定义了一个宏之后,如果预处理在接下来的源代码中看到#undef指令,那么#undef指令后面这个宏就会失效。
二、带参数的宏定义
1.定义
带参数的宏定义,其语法格式如下:
#define 标识符(形参列表)字符串
形参列表中的参数之间用逗号进行分隔。对于带参数的宏定义来说,同样需要使用字符串替换宏名,使用实参替换形参。
由于宏定义在程序预处理的时候执行,因此,相对于函数来说,宏定义的开销要小一些。
【注意】宏定义中的参数替换是“整体替换”。
实例分析:
#define ABS(x)((x)>=0?(X):-(X);
int a=12;
ABS(++a);
我们期望的值是12,但实际a的结果为14,显然这个用来替代求绝对值函数是错误的。
原因是在进行预处理时“ABS(++a)”替换为“(++a)((++a)>=0?(++a):-(++a);”,所以结果为14
案例实现:
#include <stdio.h>
#define SWAP(a,b) {int temp;temp=a;a=b;b=temp;}
int main() {
int a[5] = { 3,4,5,6,7 };
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5 - i - 1; j++) {
if (a[j] < a[j + 1])
SWAP(a[j], a[j + 1]);
}
}
for (int i = 0; i < 5; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
运行结果:
2.宏定义参数替换的注意事项
- 若宏定义中字符串出现运算符,需要在合适的位置加上括号,如果不加括号可能会出现错误。
#define S 3+4
a=S*c;//宏定义替换后的语句是a=3+4*c,与期望不符合。
修改为#define S (3+4)
则原语句替换为a=(3+4)*c
- 宏定义的末尾不用加分号,如果加了分号,将会被视为被替换的字符串的一部分。宏定义只是简单的字符串替换,并不进行语法检查,因此宏替换的错误要等到系统编译时才能被发现。
- 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在替换时由预处理程序嵌套替换。但宏定义不支持递归。
#define PI 3.14159
#define P PI*x
double c=2*P;宏替换后的语句为c=2*3.14159*x;
宏定义不支持递归
所以#define MAX MAX+5是错误定义方法
三、带参数的宏定义和带参函数的区别
基本操作 | 带参数的宏定义 | 带参数的函数 |
处理时间 | 预处理期间 | 程序运行时 |
参数类型 | 无 | 需要定义的类型 |
参数传递 | 不分配空间,无值传递的问题(只是字符串替换) | 分配内存,将实参传入形参 |
运行速度 | 快 | 相对较慢,因为函数的调用会涉及到参数的传递,压栈和出栈等操作 |