编译过程:预处理、编译、汇编、链接
文章目录
- 一、编译的过程
- 1.原理
- 2.gcc/g++ 编译指令
- (1)预处理 (-E):文本替换
- (2)编译 (-S):高级语言->汇编语言
- (3)汇编 (-c):汇编语言->机器码
- (4)链接 (无参数):目标文件+库->可执行文件
- (5)四步合为一步
- 3.举例
- (1)第一步:预处理
- (2)第二步:编译
- (3)第三步:汇编
- (4)第四步:链接
一、编译的过程
1.原理
从源文件.cpp到可执行文件.exe的编译过程,实际可拆分为4小步:①预编译 ②编译 ③汇编 ④链接
2.gcc/g++ 编译指令
| 编译步骤 | 参数 | 核心作用 | 输入文件 | 默认输出 | 命令 |
|---|---|---|---|---|---|
| 1.预处理 | -E | 处理宏定义(#define)、头文件包含(#include)、条件编译(#ifdef),进行纯文本替换 | hello.c / .cpp | hello.i | g++ -E hello.cpp -o hello.i |
| 2.编译(狭义) | -S | 将高级语言(C/C++)翻译为汇编语言,生成汇编指令文件(.s文件) | hello.i | hello.s | g++ -S hello.i -o my_asm.s |
| 3.汇编(狭义) | -c | 将汇编语言翻译为机器码,生成目标文件(.o/ .obj)。此时还未链接,无法运行 | hello.s | hello.o | g++ -c hello.s -o my_lib.o(大型项目最常用,只编译修改过的文件) |
| 4.链接 | 无参数 | 将多个目标文件(.o)和静态库/动态库合并,解决符号引用,生成最终的可执行程序 | hello.o 或 .cpp | Linux: a.out Windows: a.exe | g++ hello.o -o hello.exe |
-o是output,即重定向输出
(1)预处理 (-E):文本替换
1.预编译/编译预处理:生成 【*.i】文件(预处理后的源文件,将头文件进行了文本替换。代码总量就变长了,变为上万行)
预处理器做了纯文本替换工作:
(1)头文件包含 (#include):找到对应的头文件 (比如 iostream),把它的全部内容复制粘贴过来,替换掉这行 #include
(2)宏展开 (#define):把代码中所有的宏标识符,替换成定义好的文本
(3)条件编译 (#ifdef / #ifndef / #endif):根据条件判断,决定保留或丢弃某段代码,只保留符合条件的代码。
(4)删除注释,并添加行号标记:把 // 和 /* */ 删掉,并插入 #line 指令,告诉编译器哪一行代码原本来自哪个文件(方便报错时定位)。
g++-E test.cpp-o test.i(2)编译 (-S):高级语言->汇编语言
2.编译-S:把高级语言翻译为汇编语言
生成【*.s】文件(汇编文件,高级语言→汇编语言)
g++-S test.i-o test.s(3)汇编 (-c):汇编语言->机器码
3.汇编:把汇编语言翻译为机器代码(0101),生成目标文件.o / .obj (Linux上为.o文件,Windows上为.obj文件)
生成 【*.o】文件(目标文件,二进制文件)
g++-c test.s-o test.o前三步 (预处理、编译、汇编) 也可合并为一步:
g++-c test.c-o test.o(4)链接 (无参数):目标文件+库->可执行文件
4.链接:把静态库 静态链接or把动态库 动态链接
生成可执行程序(Windows:.exe Linux:a.out)
g++test.o-o test(1)如果是静态库(.a / .lib),链接器会把库中你用到的机器码直接复制进你的可执行文件。
(2)如果是动态库(.so / .dll),链接器不会复制代码,而是只在可执行文件里记录一份“购物清单”(告诉操作系统运行时去哪个路径加载这个库)。
(5)四步合为一步
以上编译四步(预处理、编译、汇编、链接) 也可合并为一步:
g++test.cpp-o test3.举例
test_const.cpp
(1)第一步:预处理
生成:test.i
(2)第二步:编译
生成 test.s
(3)第三步:汇编
生成二进制机器码文件 test.obj
.obj原文件可能是乱码,用objdump -s或者objdump -d命令阅读
(4)第四步:链接
生成可执行文件:test.exe
