编译、链接与诊断基础
概念说明
我们写出来的 .c 文件并不能被 CPU 直接执行。
源代码需要先经过预处理、编译、汇编和链接,最后才会生成可执行文件。
可以先把这个流程理解成两层:
编译:把单个源文件翻译成机器可理解的目标代码。链接:把多个目标文件和库拼装起来,补齐函数和变量之间的引用关系,生成最终程序。
当程序报错时,也要先分清自己卡在哪个阶段:
- 编译期错误:语法不对、类型不匹配、缺少声明。
- 链接期错误:函数声明了但没有定义,或者同名定义重复。
- 运行期错误:程序已经生成,但执行时逻辑出错、崩溃或结果异常。
初学阶段如果能先把这三类问题分开,你排错的效率会明显提高。
语法/规则
- 一个
.c源文件通常会先经过预处理,再被编译成目标文件,最后参与链接。 .h头文件更适合放声明,.c源文件更适合放定义和实现。- 多文件程序在链接时必须把真正实现所在的源文件一起编进去,否则会出现“未定义引用”之类的链接错误。
- 建议初学阶段使用
-Wall -Wextra打开常用警告,把警告当成需要认真处理的信号。 -g选项会把调试信息写入可执行文件,方便后面使用调试器。- 编译器报出的“第一条错误”通常最关键,后续很多报错可能只是连锁反应。
- 项目里一旦有多个源文件,就应该开始养成“头文件写声明,源文件写实现”的基本工程习惯。
示例
| |
| |
| |
| |
输出结果:
| |
这个例子里,main.c 通过头文件知道 add 的声明,真正的实现则来自 math_tools.c。
如果编译命令里漏掉 math_tools.c,通常就会在链接阶段报错。
常见错误
- 只写了函数声明,却没有真正提供实现,导致链接失败。
- 把函数实现直接写进头文件,又被多个源文件包含,造成重复定义。
- 看到大量错误信息就慌张修改,结果没有先处理最早出现的那条关键报错。
- 把编译错误、链接错误和运行时错误混成一类,导致排错方向完全错位。
- 明明已经开启了警告,却把警告全部忽略,错过了很多早期暴露问题的机会。