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

C语言#define的用法(非常详细,新手必看)

预处理功能是 C语言特有的功能,是 C语言和其他高级语言的区别之一。

预处理程序包含许多有用的功能,如宏定义、条件编译等。使用预处理功能可方便程序的修改、阅读、移植和调试,也可方便实现模块化程序设计。

本节要讲的 #define 命令,功能是定义可替换的宏。宏定义是预处理命令的一种,它提供了一种可以替换源码中的字符串的机制。

C语言中的宏定义,类似于 Word 文档中的替换功能,如下图所示,3.14 用 PI 替换。


图 1 文档中的替换功能

根据宏定义中是否有参数,可以将宏定义分为不带参数的宏定义和带参数的宏定义两种。

C语言不带参数的宏定义

宏定义命令 #define 用来定义一个标识符和一个字符串,就是用标识符来替代字符串。宏定义相当于给指定的字符串起一个别名。

宏定义不带参数的一般形式如下:
#define 宏名 字符序列
有以下几点说明:

注意,宏定义语句不是C语句,不需要在行末加分号。

例如:
#define  PI  3.14159
该语句的作用是用 PI 替代 3.14159,在程序执行前的预处理阶段,每当在源程序中遇到 PI 就自动用 3.14159 代替。

使用 #define 进行宏定义的好处是,需要改变一个常量时只需改变 #define 命令行,整个程序的常量都会随之改变,大大提高了程序的灵活性。宏名要简单且意义明确,一般习惯用大写字母表示,以便与变量名进行区分。

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

宏替换是以字符串代替标识符。因此,如果希望定义一个标准的邀请语,可编写如下代码:
#define  STANDARD  "Come on baby, join us."
printf(STANDARD);
编译程序遇到标识符 STANDARD 时,就用“You are welcome to join us.”替换。

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

This TEST is not that TEST

可以看到,输出结果中的 TEST 并没有用“Come on baby, join us.”替换,因此如果字符串中含有宏名(这里的宏名是 TEST),则不进行替换。

2) 如果字符串长于一行,则可以在该行末尾用反斜杠“\”来表示续行。

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

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

4) 可以用 #undef 命令取消之前宏定义的作用域,例如:
#include<stdio.h>
#define TEST " Come on baby, join us."
void main()
{
    printf(TEST);
    #undef TEST
}

5) 宏定义用于预处理命令,它不同于定义的变量,只用作字符替换,不分配内存空间。

C语言带参数的宏定义

带参数的宏定义不只是进行简单的字符串替换,还要进行参数替换。其一般形式如下:
#define 宏名(参数表) 字符序列
例如,定义一个带参数的宏,实现的功能是比较 15 和 9 这两个数值,并且返回最小值。具体代码如下:
#include<stdio.h>                                 /*包含头文件*/
#define MIX(x,y)   (x<y?x:y)                       /*定义一个宏*/
int main()                                        /*主函数main()*/
{
   int x = 15, y = 9;                             /*定义变量*/
   printf("x,y为:\n");                            /*提示输出*/
   printf("%d,%d\n", x, y);                       /*输出*/
   printf("the min number is:%d\n", MIX(x, y));   /*宏定义调用*/
   return 0;                                      /*程序结束*/
}
运行结果为:

x,y为:
15,9
the min number is:9

带参数的宏可以用来替换函数,这样做的一个好处是宏替换提高了代码的运行速度,因为不存在函数调用。但提高速度也有代价,重复编码导致增加了程序长度。关于带参数的宏和函数的区别,读者可阅读《C语言宏函数和普通函数的区别》一文详细了解。

对于带参数的宏定义有以下几点需要强调:
1) 进行宏定义时参数要加括号,如不加括号,则有时结果是正确的,有时结果是错误的。

例如,定义一个宏定义 SUM(x,y),实现参数相加的功能,代码如下:
#define SUM(x,y) x+y
在参数加括号的情况下调用 SUM(x,y),可以正确地输出结果;在参数不加括号的情况下调用 SUM(x,y),则输出的结果是错误的。比如说:
5*SUM(x,y)
则会被扩展为:
5*x+y
而本意是希望得到:
5*(x+y)

解决的办法就是在对 SUM(x,y) 进行宏扩展时加上括号:
#define SUM(x,y) (x+y)
这样就能避免这种错误发生。

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

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

4) 在带参数的宏定义中,形参不分配内存单元,因此不必进行类型定义。

相关文章