## .c → 可执行程序 ## 判别规则(核心,唯一要记的) - **带 `#` 的操作(include/define/ifdef)→ 预处理;语法/类型检查、C 转汇编 → 编译;生成 .o 机器码 → 汇编;跨文件符号合并、地址重定位、undefined reference → 链接** 一句话:**"# 开头的预处理,语法类型的编译,.o 的汇编,符号的链接。"** ## 抽象描述(一句话本质) .c → 可执行程序四步:预处理(文本处理)→ 编译(C 转汇编)→ 汇编(汇编转机器码 .o)→ 链接(合并 .o + 库 → 可执行)。每步只干自己那摊事,报错也按阶段定位。 ## 四步流水线 ``` hello.c → 预处理(cpp):展开 #include/#define/条件编译/删注释/加行号 → hello.i → 编译(cc):C 语言 → 汇编指令(语法/类型检查在这) → hello.s → 汇编(as):汇编 → 机器码 → hello.o(目标文件,还不能跑) → 链接(ld):合并 hello.o + 库/启动代码 → hello(可执行) ``` | 阶段 | 工具 | 输入→输出 | 干什么 | | ------ | ---- | ----------- | -------------------------------------------- | | 预处理 | cpp | .c → .i | 展开宏、包含头文件、条件编译、删注释、加行号 | | 编译 | cc | .i → .s | C 转汇编(语法/类型检查) | | 汇编 | as | .s → .o | 汇编转机器码 | | 链接 | ld | .o → 可执行 | 合并符号、地址重定位 | ## 报错定位(易混对比) | 操作/报错 | 属于哪步 | | -------------------------------------- | ------------------------------------------------ | | `#include` / `#define` / `#ifdef` 展开 | **预处理** | | 头文件找不到(include 报错) | **预处理** | | 语法检查、类型检查 | **编译** | | `#define MAX 1O0`(字母 O)内容错误 | **编译**(预处理只替换不查内容,编译解析时才报) | | C 语言转汇编指令 | **编译** | | 汇编转机器码(生成 .o) | **汇编** | | 符号合并、地址重定位 | **链接** | | `undefined reference` 报错 | **链接** | | 内联函数展开 | **编译**(优化阶段) | ## 静态库 vs 动态库 | | 静态库 `.a/.lib` | 动态库 `.so/.dll` | | ---------- | ---------------------------------- | ------------------------------------- | | 链接时 | 用到的目标代码**合并进**可执行文件 | **只记录引用**,不拷代码 | | 可执行文件 | **变大** | 小 | | 运行时 | 独立,不依赖库文件 | **依赖 .so 存在**,由加载器运行时加载 | | 更新库 | 要重新链接 | 换 .so 即可,不用重编译 | ## 变体验证(3 题,全过=学会) 1. 陷阱题:`.o` 能直接运行吗 → **不能**,缺启动文件、库、入口函数,要链接 2. 陷阱题:`#define MAX 1O0`(字母 O)→ **编译阶段**发现问题(预处理只做文本替换不查内容) 3. 静态库 vs 动态库 → 静态库**合并进**可执行文件(变大);动态库**只记录引用**运行时加载(小但依赖) ## 口述要点(面试怎么讲) - **结论先行**:四步(预处理/编译/汇编/链接),每步产物 .i/.s/.o/可执行 - **地址重定位是什么**:每个 .o 编译时从地址 0 开始编(不知道最后放哪),链接时把所有 .o 拼一起重新分配实际地址,把代码里跳转/访存的地方改成真实地址;extern 引用的符号在链接时填真实地址 - **预处理还干什么**:展开宏、包含头文件、条件编译、**删除注释、添加行号标记**(报错时定位文件第几行靠它) - **交叉编译**:编译器本身在 x86 上跑,但**目标平台设为 ARM**,生成 ARM 指令的机器码,烧进 ARM 就能跑。关键在于编译器知道目标平台的字长、指令集、ABI(对齐、大小端) - **易错点**:undefined reference 是链接错不是编译错;.o 不能运行;静态/动态库记反 ## 关系网络 | 相邻概念 | 和本主题的关系 | 孤立理解会犯的错 | | ----------- | ---------------------------------------- | --------------------------------- | | extern | undefined reference 就发生在链接阶段 | 以为 undefined reference 是编译错 | | 程序分段 | 链接产物 = 分段图的基础(text/data/bss) | 以为分段是编译期定的 | | 内联函数 | 内联展开在编译优化阶段 | 以为内联是预处理/链接干的事 | | 静态/动态库 | 链接阶段:.a 合并进程序,.so 运行时加载 | 把静态库/动态库记反 | ## 学习日期 2026-08-03 --- _每主题一页,复习时只翻本目录。_