C语言中宏的定义和介绍
C语言源程序中允许使用一个标识符来表示一个字符串,这称为宏。被定义为宏的标识符称为宏名。在编译预处理时,对程序中出现的宏名,都用宏定义中的字符串去替换,这成为宏替换或者宏展开。
宏定义时由源程序的宏定义命令define完成的。宏替换时由预处理程序自动完成的。在C语言中,宏分为有参数和无参数两 类
无参数宏定义:#define 宏名 替换文本
其中宏名时标识符,替换文本时任意的字符序列,其中包含可以包含程序中能出现的任何字符和空格。
例如:#define LEFT 1 #define RIGHT 0
这样,每当在源程序中遇到LEFT和RIGHT时,预处理程序都分别用1或者0替换。下面举例说明:
printf("%d%d%d\n",RIGHT,LEFT,LEFT+1);
运行结果如下:
这里实际上就是用宏定义了两个符号常量的定义。
下面是几个简单的例子:
- 用宏定义表示新的数据类型
#define STU struct student
此后,程序中出现了:
STU x,y;经过宏替换后,这行变成了 struct student x,y; - 可以宏定义来代表任意的语句序列或格式串等。
#define FORMAT “%d%d%d”
则在程序中类似如
printf("%d%d%d",1,2,3);
//上面的语句等价于
printf(FORMAT,1,2,3);
但是,为了保证代码有一定的可阅读性不推荐使用上面的这种方法来定义宏
关于宏的几点说明
- 宏定义必须卸载函数之外,其作用域为从宏定义命令开始到源程序结束。若要终止器作用域则可以使用#undef命令。
#deine PI 3.14159
int main()
{}
#undef PI
f1()
{}
//宏PI的作用域指明了是main函数,所以PI不能在f1()函数中使用
宏PI的作用域指明了是main函数,所以PI不能在f1()函数中使用
- 宏名在源程序中若用括号括起来,则预处理程序不对器做宏处理。
#define HELLO 100
int main()
{
printf("HELLO");
}
//因为预处理命令被双引号括起来了,所以这里编译器会把它当作一个字符串来处理,这里的HELLO不会被100代替
因为预处理命令被双引号括起来了,所以这里编译器会把它当作一个字符串来处理,这里的HELLO不会被100代替
- 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏替换时有预处理程序层层替换
#define One1
#define TWO (ONE+ONE
#define THREE(ONE+TWO
#define SIX(TWO*THREE)
带参数宏的定义
C语言允许宏带参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏替换,而且还用实际参数去代替形式参数。
带参数宏的一般形式:
#define 宏名(形式参数) 字符串
例如:
#define M(x,y) x*x+3*y /*宏的定义*/
int main()
{
k=M(4,5);/*宏的调用*/
}
再来一个例子
#define ABS(x) (x)<0?(-x):(x)
int main()
{
int x,y;
printf("inputx,y:");
scanf("%x%y",&x,&y);
printf("ABS(x-y)=%d\n",ABS(x-y));
}
关于带参数的宏的几点说明
- 带参数的宏中,宏名和形式参数之间不能出现空格
- 带参数宏的使用和函数调用类似,起作用似乎也像函数调用,但两者实际上很不同。首先宏定义和调用不考虑类型问题,在带参数的宏中,形势参数不分配内存单元,因此不必做类型定义,而宏调用中的实际实际参数有具体的值,要用他们去替换形式参数,因此必须做类型说明。在函数中,形式参数和实际参数时两个不同的变量,都必须进行类型说明。
- 在宏定义中,字符串内容的形式参数通常要用括号括起来避免出错。
//虽然只有一个变量x,但是为了在做宏替换的时候防止出错需要用括号把变量括起来
#define ABS(x) (x)<0?(-x):(x)