C 语言编译与链接全过程
更新时间:2026-08-26。本文是
languages/c/主题高手层的骨架文档(占位),完整展开将在后续批次补齐。
本文要回答的问题
- 每个
.c文件是独立编译的吗?"编译单元"是什么意思? - 链接器怎么把一个"未定义引用"对上某个
.o的定义? - 静态库和动态库在链接时各自做什么?
一、编译单元与四阶段
每个 .c 文件 + 它 include 的头文件 = 一个编译单元,独立走完四阶段,产出 .o:
| 阶段 | 输入 → 输出 | 关键点 |
|---|---|---|
| 预处理 | .c → .i | 展开 include/宏 |
| 编译 | .i → .s | 语法语义检查、生成汇编 |
| 汇编 | .s → .o | 生成机器码,留下未定义引用 |
| 链接 | .o+库 → 可执行文件 | 符号解析 + 重定位 |
重要推论:头文件改了,所有 include 它的 .c 都要重编——这就是增量编译的价值(见 多文件工程)。
二、符号解析
链接器收集所有 .o 的符号表:
- 已定义符号(
T函数、D数据):提供实现。 - 未定义符号(
U):引用别处,必须被某个.o或库满足。 - 找不到 →
undefined reference;多个强定义 →multiple definition。
三、静态库 vs 动态库的链接视角
| 维度 | 静态库 .a | 动态库 .so |
|---|---|---|
| 链接时 | 把用到的 .o 拷贝进可执行文件 | 只记录依赖和符号引用 |
| 运行时 | 无依赖 | 加载器按需映射 |
| 未定义符号 | 链接期必须全解 | 可延迟到加载期 |
| 升级 | 要重链接 | 换 .so 即可 |
完整展开见专家层 编译、链接与 ELF 与本站 ELF 与装载。
四、与入门层的衔接
- 头文件与多文件组织,见 头文件包含。
- 多文件工程实践,见 多文件工程与头文件设计。
一句话总结
每个 .c 独立编译成 .o、留下待解析的符号,链接器统一"配平"未定义引用:静态库是拷进来、动态库是记下依赖——编译单元的边界就是头文件依赖的边界。
本文为骨架文档:核心结构已就位,示例代码与实测数据将在后续批次补齐。