C&C++快速入门
17、有参宏与无参宏
1、课程目标
- 掌握宏定义的语法
- 理解宏与函数的区别
- 掌握宏的常见用法和注意事项
- 了解预处理指令
2、名词解释
| 术语 | 说明 |
|---|---|
| 预处理 | 编译前的文本替换 |
| 无参宏 | 简单的文本替换 |
| 有参宏 | 带参数的宏 |
| # | 字符串化操作符 |
| ## | 连接操作符 |
| 宏展开 | 宏替换为实际代码 |
3、代码实现
1. 基础宏定义
#include <stdio.h>
// 无参宏
#define PI 3.14159
#define MAX_SIZE 100
#define DEBUG 1
// 有参宏
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define SQUARE(x) ((x) * (x))
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
int main() {
printf("=== 基础宏 ===\n\n");
printf("PI = %f\n", PI);
printf("MAX(10, 20) = %d\n", MAX(10, 20));
printf("SQUARE(5) = %d\n", SQUARE(5));
int arr[] = {1, 2, 3, 4, 5};
printf("ARRAY_SIZE = %d\n", (int)ARRAY_SIZE(arr));
return 0;
}
2. 宏的陷阱
#include <stdio.h>
// 错误示例
#define BAD_SQUARE(x) x * x
#define GOOD_SQUARE(x) ((x) * (x))
int main() {
printf("=== 宏陷阱 ===\n\n");
// 缺少括号的问题
printf("BAD: 3+2的平方 = %d (应该25)\n", BAD_SQUARE(3+2)); // 11!
printf("GOOD: 3+2的平方 = %d\n", GOOD_SQUARE(3+2)); // 25
// 副作用问题
int x = 5;
// GOOD_SQUARE(x++) // 危险! x会加两次
printf("\n宏不安全用于有副作用的表达式\n");
return 0;
}
3. 特殊操作符
#include <stdio.h>
// # 字符串化
#define STRINGIFY(x) #x
#define PRINT_VAR(x) printf(#x " = %d\n", x)
// ## 连接
#define CONCAT(a, b) a##b
#define MAKE_FUNC(name) void func_##name() { printf("func_" #name "\n"); }
MAKE_FUNC(test)
MAKE_FUNC(hello)
int main() {
printf("=== 特殊操作符 ===\n\n");
// 字符串化
printf("【#字符串化】\n");
printf("%s\n", STRINGIFY(Hello World));
int value = 42;
PRINT_VAR(value);
// 连接
printf("\n【##连接】\n");
int CONCAT(my, Var) = 100; // 创建 myVar
printf("myVar = %d\n", myVar);
func_test();
func_hello();
return 0;
}
4. 条件编译
#include <stdio.h>
#define DEBUG_LEVEL 2
#if DEBUG_LEVEL >= 2
#define LOG_DEBUG(msg) printf("[DEBUG] %s\n", msg)
#else
#define LOG_DEBUG(msg)
#endif
#if DEBUG_LEVEL >= 1
#define LOG_INFO(msg) printf("[INFO] %s\n", msg)
#else
#define LOG_INFO(msg)
#endif
#define LOG_ERROR(msg) printf("[ERROR] %s\n", msg)
int main() {
printf("=== 条件编译 ===\n\n");
LOG_DEBUG("调试信息");
LOG_INFO("普通信息");
LOG_ERROR("错误信息");
// 平台检测
#ifdef _WIN32
printf("\nWindows平台\n");
#endif
#ifdef _WIN64
printf("64位编译\n");
#else
printf("32位编译\n");
#endif
return 0;
}
5、课后作业
5.1、作业1:实现断言宏
实现一个MY_ASSERT宏,失败时打印文件名和行号。
5.2、作业2:实现日志宏
实现支持格式化输出的日志宏,包含时间戳。