预处理器
宏、#include、条件编译。
30 分钟
预处理器
编译前,预处理器处理 #include、#define 与条件编译。对照 /roadmaps/c,读懂头文件守卫与跨平台宏是维护 C 项目的必备技能。
学习目标
- 理解
#include与头文件组织 - 编写带参数的宏并知道其局限
- 使用
#if、#ifdef做条件编译 - 区分宏与
const、内联函数
核心概念
宏与条件编译
/* config.h */
#ifndef CONFIG_H
#define CONFIG_H
#define VERSION "1.0.0"
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define LOG(fmt, ...) printf("[LOG] " fmt "\n", ##__VA_ARGS__)
#if defined(_WIN32)
# define PATH_SEP '\\'
#else
# define PATH_SEP '/'
#endif
#ifdef DEBUG
# define DBG(msg) fprintf(stderr, "DEBUG: %s\n", msg)
#else
# define DBG(msg) ((void)0)
#endif
#endif /* CONFIG_H */
/* main.c */
#include <stdio.h>
#include "config.h"
static int square(int x) {
return x * x;
}
int main(void) {
LOG("version=%s sep=%c", VERSION, PATH_SEP);
DBG("entering main");
int a = 3, b = 7;
printf("MAX=%d square=%d\n", MAX(a, b), square(a));
/* 宏陷阱:多次求值 */
int i = 5;
printf("MAX(i++, 10)=%d i=%d\n", MAX(i++, 10), i);
#if 0
puts("disabled block");
#endif
return 0;
}
最佳实践
| 做法 | 说明 |
|---|---|
| 头文件守卫 | #ifndef / #define / #endif 防重复包含 |
| 宏参数加括号 | #define SQR(x) ((x)*(x)) |
| 复杂逻辑 | 用 static inline 函数代替宏 |
| 平台差异 | #ifdef _WIN32 等集中管理 |
#include "local.h" 先搜当前目录;#include <stdio.h> 搜系统路径。
与 C++/Java 对照
| 特性 | C 预处理器 | C++ | Java |
|---|---|---|---|
| 文本替换 | #define 宏 | 有 + 模板/constexpr | 无 |
| 条件编译 | #ifdef | 有 | 无(靠 profile/模块) |
| 头文件 | #include 展开 | 同左 + #pragma once | import / module |