首页 > 编程笔记 > C语言笔记 阅读:22

#define宏定义在C语言中是什么意思(非常详细)

宏定义是预处理命令的一种,它提供了一种可以替换源代码中字符串的机制。

简单来说,宏定义指令 #define 用来定义一个标识符和一个字符串,以这个标识符来代表这个字符串,在程序中每次遇到该标识符时就用所定义的字符串替换它。

宏定义的作用相当于给指定的字符串起了一个别名。

C语言不带参数的宏定义

首先来讲解不带参数的宏定义,其一般形式如下:
#define  宏名  字符串

注意,C语言并没有规定 #define 必须写在函数外面,只是规定这条命令必须单独占一个完整的逻辑行。其作用范围是 #define 出现的位置到所在源文件结束,或到相应的 #undef 预处理指令处。如果需要 #define 预处理命令仅在某个函数内有效,完全可以把它写在函数内。

例如,下面宏定义的作用是在程序中用 PI 替代 3.14159:
#define PI 3.14159
编译预处理时,每当在源程序中遇到 PI,就自动用 3.14159 代替。注意,宏定义不是 C 语句,不需要在行末加分号。

使用 #define 进行宏定义的好处是:当需要改变一个常量时,只需改变 #define 命令行,整个程序的常量都会改变,大大提高了程序的灵活性。

宏名定义后,即可成为其他宏名定义中的一部分。例如,下面代码定义了正方形的边长 SIDE、周长 PERIMETER 及面积 AREA 的值。
#define  SIDE  5
#define  PERIMETER  4*SIDE
#define  AREA  SIDE*SIDE

前面强调过,宏替换是以字符串代替标识符。因此,可定义一个标准的邀请语:
#define  STANDARD  "You are welcome to join us."
printf(STANDARD);
编译程序时,遇到标识符 STANDARD,就用"You are welcome to join us."替换。

关于不带参数的宏定义,有以下几点需要注意。
1) 如果在字符串中出现宏名,则不进行替换。例如:
#include<stdio.h>
#define TEST "this is an example"
main()
{
    char exp[30]="This TEST is not that TEST"; /* 定义字符数组并赋初值 */
    printf("%s\n",exp);
}
运行结果为:

This TEST is not that TEST

可见,字符串中的两处 TEST 并没有用"this is an example"替换。

2) 如果字符串多于一行,可在行末用反斜杠“\”进行续行。

3) #define命令出现函数外时,宏名的有效范围为定义命令之后到此源文件结束。

注意,通常会将所有 #define 放到文件开始处或独立的文件中,而不是将它们分散到整个程序中。

4) 可以用 #undef 命令终止宏定义的作用域,例如:
#include<stdio.h>
#define TEST "this is an example"
main()
{
    printf(TEST);
    #undef TEST
}
运行结果为:

this is an example


5) 宏定义是一种预处理命令,不同于变量定义,它只做字符替换,而不分配内存空间。

C语言带参数的宏定义

带参数的宏定义,不仅要进行字符串替换,还要进行参数替换。其一般形式如下:

#define 宏名(参数表)字符串


【实例 1】要求对两个数实现乘法和加法混合运算,代码如下:
#include<stdio.h>
#define MIX(a,b) ((a)*(b)+(b))    /*宏定义,求两个数的混合运算*/
main()
{
    int x=5,y=9;
    printf("x,y:\n");
    printf("%d,%d\n",x,y);
    printf("the min number is:%d\n",MIX(x,y));    /*宏定义调用*/
}
程序运行结果为:

x,y:
5,9
the min number is:54

可见,编译程序时,printf() 语句将被替换为如下形式:
printf("the min number is: %d",((a)*(b)+(b)));
用宏替换代替实在的函数,好处是可以提升代码速度(不再存在函数调用),代价是由于重复编码,增加了程序长度。

对于带参数的宏定义,有以下几点需要注意:
1) 宏定义时,参数要加括号。如不加括号,则结果可能是正确的,也可能是错误的。

实例 1 中,如果宏定义语句改为:
#define MIX(a,b) (a*b+b)    /*宏定义,求两个数的混合运算*/
则 main() 函数中,x=10,y=9 时调用 MIX(x, y),可以输出正确结果 99;x=10,y=3+4 时调用 MIX(x, y),执行情况为 (10*3+4+3+4),将输出错误结果为 41。因此,宏定义时一定要给参数加上括号。

2) 宏扩展必须使用括号来保护表达式中优先级低的操作符,以确保调用时能达到预期效果。

实例 1 中,如果宏扩展外没有加括号,则调用 5*MIX(x, y),会被扩展为 5*(a)*(b)+(b),而本意是希望得到 5*((a)*(b)+(b)),显然出现了错误。

3) 对带参数的宏的展开,只是用宏名后括号内的实参字符串代替 #define 命令行中的形参。

4) 宏定义时,宏名与带参数的括号之间不要加空格,否则会将空格以后的字符都作为替代字符串的一部分。

5) 在带参宏定义中,形式参数不分配内存单元,因此不必做类型定义。

相关文章