C/C++ 里 .h / .c / .cpp 的关系 + 完整编译流程 。
你看完就能明白为什么多文件会报错、为什么要写头文件、编译器到底在干嘛。
一、先记住一句话(核心真理)
.h(头文件)不参与编译!
只有 .c / .cpp(源文件)会被编译!
.h 的唯一作用:给其他文件"声明"接口,让编译器知道有这个函数/变量。
二、三者到底是什么关系?
1. .h 文件 = 说明书(声明)
只写:
- 函数声明
- 宏定义
- 结构体/枚举
- 外部变量
extern
不写函数实现!
例子:max.h
c
// 仅仅告诉编译器:有一个叫 findMaxNum 的函数
int findMaxNum(int a, int b);
2. .c / .cpp = 实现(真正的代码)
写函数真正的逻辑。
例子:max.c
c
// 真正实现
int findMaxNum(int a, int b) {
return a > b ? a : b;
}
3. 调用方(比如 main.c)
c
#include "max.h" // 引入说明书
int main() {
findMaxNum(3,5); // 用函数
}
三、它们是怎么关联起来的?(超简单)
#include "max.h"→ 把 .h 内容复制粘贴到当前文件- 编译器看到函数声明 → 知道"这个函数存在"
- 链接阶段 → 把所有
.c编译出来的.o文件拼在一起
四、完整编译流程(4步,一看就懂)
编译器执行 4 个步骤:
1. 预处理(Preprocess)
- 处理
#include - 把头文件内容复制到源文件
- 结果:一个完整的 .c 文件
2. 编译(Compile)
- 把每个
.c独立编译成 .o 目标文件 - 每个 .c 是独立编译的!互相不知道对方存在!
3. 汇编(Assemble)
生成机器码,但还不能运行。
4. 链接(Link)最关键!
- 把所有
.o合并成一个.exe - 查找函数在哪里、变量在哪里
- 找不到 → 报 undefined reference(你刚才遇到的错)
五、用你的项目举例子
你有:
- max.h
- max.c
- test2.c
编译流程:
- test2.c
#include "max.h" - 编译 test2.c → test2.o
- 编译 max.c → max.o
- 链接 test2.o + max.o → test2.exe
如果只编译 test2.c,不编译 max.c → 链接找不到函数 → 报错!
六、为什么要分 .h 和 .c?
3 个原因:
- 代码分离:声明和实现分开
- 多人协作:A写声明,B写实现
- 防止重复定义:.h 只声明,不实现,不会冲突
七、最经典的 2 个错误(你一定会遇到)
错误1:undefined reference to XXX
原因:函数实现的 .c 文件没有参与编译
错误2:重复定义函数
原因:把函数实现写在了 .h 里,被多个文件 include → 重复定义
八、一句话总结
- .h = 声明(告诉编译器有这个东西)
- .c/.cpp = 实现(真正代码)
- #include = 复制粘贴
- 编译:每个 .c 独立编译成 .o
- 链接:把所有 .o 合成 exe
- 报错 90% 是因为少编译了某个 .c