编译过程:预处理、编译、汇编、链接

文章目录

  • 一、编译的过程
    • 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 / .cpphello.ig++ -E hello.cpp -o hello.i
2.编译(狭义)-S将高级语言(C/C++)翻译为汇编语言,生成汇编指令文件(.s文件)hello.ihello.sg++ -S hello.i -o my_asm.s
3.汇编(狭义)-c将汇编语言翻译为机器码,生成目标文件(.o/ .obj)。此时还未链接,无法运行hello.shello.og++ -c hello.s -o my_lib.o(大型项目最常用,只编译修改过的文件)
4.链接无参数将多个目标文件(.o)和静态库/动态库合并,解决符号引用,生成最终的可执行程序hello.o 或 .cppLinux: 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 test

3.举例

test_const.cpp

(1)第一步:预处理

生成:test.i


(2)第二步:编译

生成 test.s


(3)第三步:汇编

生成二进制机器码文件 test.obj

.obj原文件可能是乱码,用objdump -s或者objdump -d命令阅读


(4)第四步:链接

生成可执行文件:test.exe