C++ #define宏定义用法详解(附带实例)
宏定义是预处理命令的一种,它提供了一种可以替换源代码中字符串的机制。简单来说,宏定义指令 #define 用来定义一个标识符和一个字符串,以这个标识符来代表这个字符串,在程序中每次遇到该标识符时就用所定义的字符串替换它。
宏定义的作用相当于给指定的字符串起了一个别名。
例如,下面的宏定义中用 3.14159 替代 PI。编译预处理时在源程序中遇到 PI,会自动用 3.14159 代替:
宏名要简单且意义明确,一般习惯用大写字母表示,以便与变量名相区别。
宏名定义后,即可成为其他宏名定义中的一部分。例如,下面的程序代码定义了正方形的边长 SIDE、周长 PERIMETER 及面积 AREA 的值:
前面强调过,宏替换是以字符串代替标识符。因此,如果希望定义一个标准的邀请语,可编写如下程序代码:
以上编译程序,与 printf 语句的如下形式是等效的:
关于不带参数的宏定义,要强调以下几点:
1) 当字符串中含有宏名时,不进行替换。例如:
2) 当字符串长于一行时,可在行尾用反斜杠“\”续行。
3) #define 命令出现在程序中函数的外面,宏名的有效范围为定义命令之后到此源文件结束。
注意,实际开发中,一般将所有 #define 都统一放在文件开始代码处,或放在一个独立的文件中,而不会将它们分散到整个程序中。
4) 可以用 #undef 命令终止宏定义的作用域。例如:
5) 宏定义用于预处理命令,它不同于定义的变量,只进行字符替换,不分配内存空间。
【实例】求两个数的乘积。使用带参数的宏实现求两个数的乘积。具体代码如下:
当编译该程序时,由 MUL(x,y) 定义的表达式被替换,a 和 b 用作操作数,即“c=MUL(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) 执行情况如下:
2) 宏扩展必须使用括号来保护表达式中低优先级的操作符,以确保调用时达到想要的效果。
例如,有如下宏定义:
3) 对带参数的宏的展开,只是将宏名后面括号内的实参字符串代替 #define 命令行中的形参。
4) 在宏定义时,宏名与带参数的括号之间不能加空格,否则将空格以后的字符都作为替代字符串的一部分。
5) 在带参宏定义中,形式参数不分配内存单元,因此不必做类型定义。
宏定义的作用相当于给指定的字符串起了一个别名。
C++不带参数的宏定义
不带参数的宏定义一般形式如下:#define 宏名 字符串
- “#”表示这是一条预编译命令;
- 宏名是一个标识符,必须符合 C++ 语言标识符的规定;
- 字符串可以是常数、表达式、格式字符串等。
例如,下面的宏定义中用 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) 在带参宏定义中,形式参数不分配内存单元,因此不必做类型定义。