//接上文
#define
在 C 语言中确实常用于定义常量,但它也可以用于定义宏(即带参数的代码片段)
1. 常量定义
常量是一个固定的值,通常使用 #define
定义。例如:
#define PI 3.14(中间不加赋值运算符,空格隔开即可)
在这个例子中,PI
是一个常量,预处理器会在编译时将所有出现的 PI
替换为 3.14
2. 代码片段定义
宏是一个可以接受参数的代码片段,宏定义(Macro Definition)是C语言预处理器的一部分,通常用于简化代码或实现一些简单的功能。例如:
#define SQUARE(x) ((x) * (x))
在这个例子中,SQUARE
是一个宏,它接受一个参数 x
,并在使用时被替换为 ((x) * (x))
(两个括号,第一个里面是形参列表,第二个是内容)。这使得你可以在代码中方便地计算一个数的平方
- 带参数的宏可以接受输入并在预处理阶段进行文本替换
以下是 C 语言宏定义的语法及用法的表格汇总:
基本宏 #define 宏名 宏值 定义一个简单的宏,用于替换文本。例如:#define PI 3.14
带参数的宏 #define 宏名(参数列表) 宏体 定义一个带参数的宏,用于替换文本。例如:#define SQUARE(x) ((x) * (x))
条件编译宏 #ifdef 宏名
、#ifndef 宏名、
#endif
,用于检查宏是否被定义。例如:#ifdef DEBUG
宏取消定义 #undef 宏名 取消宏定义,使宏名不再有效。例如:#undef PI
宏扩展 #define 宏名(x) (x) 在宏体中使用宏参数。例如:#define DOUBLE(x) ((x) * 2)
多行宏 #define 宏名 (参数列表) \
宏体行1
宏体行2 定义多行宏,需要在行末加反斜杠\进行续行!!!。例如:#define MAX(a, b) \
(((a) > (b)) ? (a) : (b))
宏函数 #define 宏名(参数1, 参数2) 宏体 定义带多个参数的宏。例如:#define ADD(x, y) ((x) + (y)
宏定义可以用来定义代码片段,从而减少重复的代码,提高维护性
#define SQUARE(x) ((x) * (x))
int main() {
int num = 4;
printf("Square: %d\n", SQUARE(num));
return 0;
}
带参数的宏允许在宏定义中使用参数,类似于函数调用,但不同的是宏在预处理阶段进行文本替换
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int main() {
int x = 5, y = 10;
printf("Max: %d\n", MAX(x, y));
return 0;
}
宏不可与变量名冲突,否则编译器会报错
宏嵌套是指在一个宏定义中使用另一个宏定义。这种方式可以提高宏定义的灵活性和可重用性
#define DOUBLE(x) ((x) + (x))
#define QUADRUPLE(x) (DOUBLE(DOUBLE(x)))
int main() {
int num = 5;
printf("Quadruple: %d\n", QUADRUPLE(num));
return 0;
}
//输出Quadruple: 20
特别注意,宏替换是简单的文本替换(被调用时这在预处理时整体运行,且遵循顺序结构),自身没有运算优先级的检查,因此编写宏时必须特别注意括号的使用!!!
#define ADD(x, y) x + y
int result = ADD(3, 2 * 5);
预处理器将 ADD(3, 2 * 5)
替换为 3 + 2 * 5
(这是宏的操作原理,ADD(3,2*5)是一个整体被替换,但效果与函数类似,所以也称为宏函数),宏自己只做文本替换,替换后编译器再根据运算优先级规则,结果是 3 + 10
,而不是预期的 (3 + 2) * 5
。这是因为 +
运算符的优先级低于 *
运算符(这也容易被我们接受)
#define ADD(x, y) ((x) + (y))
这和上面的结果都是13,但是区别是这个是在预处理文本替换阶段加上了括号,即:预处理时使用了括号调整运算优先级,而不是编译器自己来做这件事(替换时大的括号里面加的括号也一起替换过去了)
同时,宏的形参列表不需要像函数一样加上定义类型,因为实际它就等同于函数体中文本的替换,同时,宏本身并没有返回值的概念,这不同于函数
出错的宏:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#define ex(a b) (b a)//错误1
int main() {
int a, b;
scanf("%d %d", &a, &b);
int result = ex(a b);//错误2
printf("%d", result);
return 0;
}
首先,正确的宏定义应该使用逗号分隔参数而不是空格(目的是进行空格分开,两参数分开,但是宏定义有自己的规范要求)
错误1的第二个括号也是错误的。调用宏ex
,传入参数a
和b
。根据宏的定义,这将被替换为(b a)
,但是这在C语言中是无效的表达式,因此会导致编译错误
错误2,极其重要!这个宏定义了一个交换操作,但它并不返回任何值,因此 int result =
ex(a, b);
的用法是错误的
宏没有返回值,因此 result
将未定义。你不能将宏的结果赋值给一个变量
ex(a, b); // 直接调用宏
这是修改代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#define ex(a,b) int temp=a;\
a=b;\
b=temp;
int main() {
int a, b;
scanf("%d %d", &a, &b);
ex(a, b);
printf("%d %d",a,b);
return 0;
}
1.多行宏的最后一行可以不加反斜杠
2.多行宏的宏体也要像函数体那样加;(且多加反斜杠)
3.编译器按顺序结构执行ex(a,b)时,ex(a,b)文本替换成多行宏体内容,可类比函数
4.顺序结构很重要,若ex(a,b)放在printf后面,则输出结果不会变,因为是在打印结果的后面执行的宏
加括号是为了考虑运算优先级,加分号是为了函数体使用宏的文本替换,同时请确保每行末尾以反斜杠作为最后字符
//宏定义中的换行符 \
用于连接多行代码,确保它们在预处理时被视为一行
Comments NOTHING