006、安全开发篇(一):include 预处理指令
返回:安全开发篇(一)目录 · 上一篇:005、注释方式 · 下一篇:007、程序入口点
对应视频:1.5 基础-#include预处理指令.mp4
1、学习目标
这一节整理 #include。它是 C/C++ 里非常常见的预处理指令,用来在编译前引入头文件内容。
需要掌握:
#include的基本作用;- 尖括号和双引号的区别;
- 头文件通常放什么;
- 它和编译流程的关系;
- 安全开发中为什么要关注头文件和声明。
2、基本写法
1 |
|
stdio.h 是标准输入输出头文件。使用 printf 前包含它,可以让编译器知道 printf 的声明。
#include 是预处理指令,不是普通 C 语句,所以结尾不写分号。
3、尖括号和双引号
| 写法 | 查找方式 | 常见用途 |
|---|---|---|
#include <xxx.h> |
优先从系统头文件目录查找 | 标准库、系统 SDK、第三方库 |
#include "xxx.h" |
优先从当前工程或当前文件所在目录查找,找不到再查系统目录 | 自己写的头文件 |
示例:
1 |
stdio.h 是系统标准库头文件,calc.h 可以是自己项目里的函数声明文件。
4、预处理流程
可以先粗略理解为:
- 编译前,预处理器扫描
#开头的指令; - 遇到
#include,把对应头文件内容纳入当前编译单元; - 处理宏定义和条件编译;
- 编译器再正式分析 C 语法。
头文件本身通常不直接生成可执行程序,它更多是在编译时提供声明和公共定义。
5、头文件通常放什么
| 内容 | 示例 | 说明 |
|---|---|---|
| 函数声明 | int add(int a, int b); |
告诉编译器函数形式 |
| 结构体声明 | struct User { ... }; |
统一数据结构 |
| 宏定义 | #define MAX_SIZE 128 |
定义常量或简单替换 |
| 类型别名 | typedef unsigned int uint32; |
简化类型表达 |
| 外部变量声明 | extern int g_count; |
声明其他文件中的变量 |
初学时可以先把头文件理解成“公共说明书”。
6、代码实验
calc.h:
1 |
|
calc.c:
1 |
|
main.c:
1 |
|
这里 main.c 不需要知道 add 的完整实现,只需要通过 calc.h 知道它的声明。
7、安全开发观察
头文件和安全开发的关系主要体现在:
- 调用系统 API 前,需要对应头文件提供声明;
- 函数声明不匹配可能造成参数解释错误;
- 结构体声明决定内存布局理解;
- 宏定义可能影响编译出来的代码路径;
- 多文件工程中,声明和实现分离能帮助分析模块边界。
逆向或代码审计时,头文件能帮助快速理解函数原型、结构体字段和常量含义。
8、复盘题
8.1 #include <stdio.h> 的作用是什么?
它在编译前引入标准输入输出头文件,让编译器知道 printf、scanf 等函数的声明。
8.2 尖括号和双引号有什么区别?
尖括号通常用于系统或库头文件,优先从系统目录查找;双引号通常用于项目自己的头文件,优先从当前工程目录查找。
8.3 为什么头文件里常见 #ifndef、#define、#endif?
这是头文件保护,避免同一个头文件被重复包含后造成重复定义或编译冲突。
这一节要记住:#include 发生在编译前,它解决的是“让当前源文件知道外部声明”的问题。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Ruiqy~!


