问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

深入解析C/C++编译过程:预处理、编译、汇编与链接

创作时间:
作者:
@小白创作中心

深入解析C/C++编译过程:预处理、编译、汇编与链接

引用
1
来源
1.
https://www.kucoding.com/article/191.html

C/C++编译过程是将源代码转换为可执行程序的一系列复杂步骤。本文将深入解析这一过程中的四个主要阶段:预处理、编译、汇编和链接。通过具体的代码示例和Linux系统中的g++编译器指令,帮助读者理解每个步骤的具体操作和作用。

一、前言

虽然使用VS这样的集成开发环境(IDE)开发C/C++程序非常简单,只需要点击一下就能完成代码的编译和生成可执行文件,但其底层实现却并不简单。了解编译过程的底层原理,有助于更深入地理解代码,更容易定位和修复bug。

本文将详细介绍C/C++的整个编译过程,主要分为四个步骤:预处理、编译、汇编和链接。以下是这四个步骤的流程图:

本文将以一个简单的C++项目为例进行说明,该项目包含三个文件:

  • fun.h:定义函数的头文件
  • fun.cpp:实现函数的源文件
  • main.cpp:入口源文件

为了方便查看每一步的处理结果,这些文件在Linux系统中也准备了一份,用于展示每一步编译后的结果。

二、预处理

预处理是编译过程的第一步,主要作用是去除对后续编译无用的内容:

  1. 去除注释
  2. 替换宏定义
  3. 展开头文件
  4. 执行预处理指令

经过预处理后,代码会变成如下形式:

主要变化包括:

  • 注释内容被去除
  • 头文件在.cpp文件中原地展开
  • 宏被替换
  • 预处理指令(以#开头的命令,如#include#define等)被执行

预处理生成的文件通常以.i作为后缀名。在Linux系统中,可以使用g++编译器执行预处理:

g++ -E main.cpp -o main.i
g++ -E fun.cpp -o fun.i

-o选项用于指定生成的结果文件。查看预处理后的文件内容,可以看到预处理指令、注释等已被处理,只剩下代码。

三、编译

预处理完成后,进入编译阶段,目的是将C++代码转换为汇编代码。这一过程会将所有.cpp源文件编译成存放汇编代码的文件,通常以.s作为后缀名。

例如,上述两个.cpp文件会被编译成:

  • main.s
  • fun.s

这两个文件中存放的就是其内部C++代码所对应的汇编代码。在Linux系统中,可以使用g++编译器执行编译:

g++ -S main.i -o main.s
g++ -S fun.i -o fun.s

查看汇编代码文件的内容,可以看到已经转换为汇编指令。需要注意的是,不同系统的汇编代码可能有所不同,C/C++的跨平台特性主要体现在源码层面,即同一份C/C++源码可以在不同系统上编译成对应的汇编代码。

四、汇编

计算机只能识别由0和1组成的机器码,汇编阶段就是将汇编代码转换为机器码的过程。生成的文件通常以.o作为后缀名,表示目标文件。

例如,上述两个汇编文件会被转换为:

  • main.o
  • fun.o

这两个文件中存放的就是对应的机器码。在Linux系统中,可以使用g++编译器执行汇编:

g++ -c main.s -o main.o
g++ -c fun.s -o fun.o

由于已经是二进制格式,直接用文本编辑器查看会显示乱码,通常需要使用十六进制查看器来查看二进制文件。

五、链接

最后一步是链接,将所有.o文件以及用到的库文件代码进行链接,生成最终的可执行程序。例如,代码中使用的iostream就是标准库,最终会链接标准库的代码。

这个过程类似于“打包”,将所有.o文件、系统库、标准库等代码整合在一起,生成可执行文件。在Windows系统下,可执行文件通常以.exe为后缀;在Linux系统下则不使用后缀名。

在Linux系统中,可以使用g++编译器执行链接:

g++ fun.o main.o -o executable

生成的可执行文件可以在相应系统中运行,得到执行结果。

六、总结

从上述过程可以看出,C/C++编译过程非常复杂,但在Windows系统下有Visual Studio等IDE可以简化开发流程。在Linux系统下,通常需要借助make、cmake等工具来组织代码编译,特别是对于包含数十上百个源文件的中大型项目,手动编译会非常繁琐。

本文原文来自kucoding.com

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号