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:实现日志宏

实现支持格式化输出的日志宏,包含时间戳。