首页 > 编程笔记 > C++笔记 阅读:2

C++ #define宏定义用法详解(附带实例)

宏定义是预处理命令的一种,它提供了一种可以替换源代码中字符串的机制。简单来说,宏定义指令 #define 用来定义一个标识符和一个字符串,以这个标识符来代表这个字符串,在程序中每次遇到该标识符时就用所定义的字符串替换它。

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

C++不带参数的宏定义

不带参数的宏定义一般形式如下:
#define 宏名 字符串

例如,下面的宏定义中用 3.14159 替代 PI。编译预处理时在源程序中遇到 PI,会自动用 3.14159 代替:
#define PI 3.14159
使用 #define 进行宏定义的好处是:当需要改变一个常量时,只需改变 #define 命令行,整个程序的常量都会改变,大大提高了程序的灵活性。

宏名要简单且意义明确,一般习惯用大写字母表示,以便与变量名相区别。

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


宏名定义后,即可成为其他宏名定义中的一部分。例如,下面的程序代码定义了正方形的边长 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.”替换。

以上编译程序,与 printf 语句的如下形式是等效的:
printf("You are welcome to join us.");

关于不带参数的宏定义,要强调以下几点:
1) 当字符串中含有宏名时,不进行替换。例如:
#include <stdio.h>
#define TEST "this is an example"
int 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"
int main()
{
    printf(TEST);
    #undef TEST
}
运行结果为:

this is an example


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

C++带参数的宏定义

带参数的宏定义不是简单的字符串替换,它还要进行参数替换。一般形式如下:
#define 宏名(参数表)字符串

【实例】求两个数的乘积。使用带参数的宏实现求两个数的乘积。具体代码如下:
#include<stdio.h>
#define MUL(x,y) ((x)*(y))  //定义两个数的乘积
int main()
{
    int a,b,c;
    printf("请输入两个整数:\n");
    scanf("%d%d",&a,&b);
    c=MUL(a,b);  //调用宏定义
    printf("两数乘积为:%d\n",c);
    return 0;
}
程序运行结果为:

请输入两个整数:
3 4
两数乘积为:12


当编译该程序时,由 MUL(x,y) 定义的表达式被替换,a 和 b 用作操作数,即“c=MUL(a,b);”语句被代替后变为如下形式:
c=((a)*(b));
用宏替换的一个好处是,因为不存在函数调用,所以可提高代码的速度。但提高速度也有代价,因为重复编码会增加代码的长度。

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

如前面的实例程序中,当参数 a=8,b=9 时,在参数不加括号的情况下调用 MUL(a,b),可以正确地输出结果;当 a=8,b=5+4 时,若参数不加括号,即定义成 #define MUL(a,b) a*b,这种情况下调用 MUL(a,b),则输出的结果是错误的。此时调用的 MUL(a,b) 执行情况如下:
c=8*5+4;
此时计算的结果是 44,而实际上希望得出的结果是 72。为了避免出现上面这种情况,在进行宏定义时,一定要在参数外面加上括号。

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

例如,有如下宏定义:
#define SUB(x,y) (x)+(y)
通过如下代码调用该宏定义时:
5*SUB(x,y);
则会被扩展为:
5*(x)+(y);
而本意是希望得到:
5*((x)+(y));
解决的办法是宏扩展时加上括号,此时就能避免这种错误发生。

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

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

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

相关文章