预处理器
翻译整理自 cppreference - 预处理。
预处理器在编译前对源码做文本替换,主要指令以 # 开头。
1. 文件包含 #include
#include <stdio.h> // 系统头文件
#include "myheader.h" // 自定义头文件(先在当前目录找)实现:把被包含文件内容文本插入当前文件。
2. 宏定义 #define
简单宏
#define PI 3.14159
#define MAX_LEN 256带参数的宏
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int y = SQUARE(3); // 9
int z = MAX(1 + 1, 3); // 3
宏中的参数与整体结果都应加括号,避免运算优先级问题。
多行宏
#define LOG(fmt, ...) \
do { \
fprintf(stderr, fmt, __VA_ARGS__); \
} while (0)__VA_ARGS__ 代表 ... 中的实参(C99)。
3. 取消宏 #undef
#define PI 3.14
#undef PI
#define PI 3.141594. 条件编译
#ifdef DEBUG
printf("debug mode\n");
#endif
#ifndef VERSION
#define VERSION "1.0"
#endif
#if defined(_WIN32) || defined(_WIN64)
// Windows
#elif defined(__linux__)
// Linux
#else
// Other
#endif
#if __STDC_VERSION__ >= 201112L
// C11
#endif5. 预定义宏
| 宏 | 含义 |
|---|---|
__FILE__ |
当前源文件名 |
__LINE__ |
当前行号 |
__DATE__ |
编译日期 |
__TIME__ |
编译时间 |
__func__ |
当前函数名(C99+,非宏) |
__STDC__ |
是否遵循标准 |
__STDC_VERSION__ |
标准 C 版本号 |
fprintf(stderr, "%s:%d %s: error\n", __FILE__, __LINE__, __func__);6. #pragma 指令
#pragma once // 头文件只包含一次
#pragma pack(push, 1) // 1 字节对齐
struct Hdr { short len; int type; };
#pragma pack(pop)
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wunused"
#endif7. _Pragma 运算符(C99)
等价于 #pragma,但可用于宏中:
_Pragma("pack(push, 1)")8. 头文件写法
// myheader.h
#ifndef MYHEADER_H
#define MYHEADER_H
int add(int, int);
#endif // MYHEADER_H
#pragma once 是非标准但广泛支持的简化方案:
#pragma once
int add(int, int);9. 宏 vs 函数
| 特性 | 宏 | 函数 |
|---|---|---|
| 类型 | 无类型 | 有类型 |
| 求值 | 多次(如 MAX(i++, j++)) |
一次 |
| 调用开销 | 无(直接替换) | 有 |
| 调试 | 难(无符号) | 易 |
10. 字符串化与拼接
#define STR(x) #x
#define XSTR(x) STR(x)
STR(hello) // "hello"
#define VERSION 100
XSTR(VERSION) // "100"
#define CAT(a, b) a##b
CAT(foo, bar) // foobar
11. 防止重复包含
// classic
#ifndef _MY_H_
#define _MY_H_
...
#endif12. 常用预定义平台宏
#ifdef _WIN32
// Windows
#elif defined(__APPLE__)
// macOS / iOS
#elif defined(__ANDROID__)
// Android
#elif defined(__linux__)
// Linux
#endif小结
预处理器是 C 的"代码生成"工具,用得好能极大减少重复代码,但滥用会降低可读性,建议优先用 const、enum、inline 替代宏。