C++-源代码到可执行文件的详细过程

概况

源代码->预编译->编译->汇编->链接->可执行文件

预编译

预处理阶段做的事情就是预处理器(cpp)根据以字符#开头的代码修改原始的C程序,这个过程会得到不包含#指令的.i文件

  1. 删除所有的#define,展开所有的宏定义;
  2. 处理所有的条件预编译指令,如#if, #endif, #ifdef, #elif#else
  3. 处理#include预编译指令,将文件内容替换到它的位置,这个过程是递归进行的,文件中包含其他文件;
  4. 删除所有的注释;
  5. 保留所有的#pragma 编译器指令,编译器需要用到他们,如:#pragma once 是为了防止有文件被重复引用;
  6. 添加行号和文件标识,便于编译时编译器产生调试用的行号信息,和编译时产生编译错误或警告是 能够显示行号。

这个过程将源代码文件转化成x.ix.ii文件。

编译:

这阶段要做的工作主要是,将预编译生成的x.i或者x.ii文件,通过词法分析、语法分析、语义分析及优化后,翻译成汇编代码

这个过程将x.i文件转化为x.s文件

汇编:

汇编过程就是把汇编语言翻译成目标机器指令的过程,生成目标文件(.obj .o等)。目标文件中存放的也就是与源程序等效的目标的机器语言代码。

这个过程将x.s文件转化成x.o(Linux)或x.obj(Windows)。

链接:

将不同的源文件产生的目标文件进行链接,从而形成一个可以执行的程序。这个过程分为静态链接和动态链接。

静态链接

函数和数据被编译进一个二进制文件。在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件。

优点
  • 运行速度快:但是静态链接的优点就是,在可执行程序中已经具备了所有执行程序所需要的任何东西,在执行的时候运行速度快。
缺点
  • 空间浪费:因为每个可执行程序中对所有需要的目标文件都要有一份副本,所以如果多个程序对同一个目标文件都有依赖,会出现同一个目标文件都在内存存在多个副本;
  • 更新困难:每当库函数的代码修改了,这个时候就需要重新进行编译链接形成可执行程序。

动态链接

动态链接的基本思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不是像静态链接一样把所有程序模块都链接成一个单独的可执行文件。

优点
  • 共享库:就是即使需要每个程序都依赖同一个库,但是该库不会像静态链接那样在内存中存在多份副本,而是这多个程序在执行时共享同一份副本;

  • 更新方便:更新时只需要替换原来的目标文件,而无需将所有的程序再重新链接一遍。当程序下一次运行时,新版本的目标文件会被自动加载到内存并且链接起来,程序就完成了升级的目标。

缺点
  • 性能损耗:因为把链接推迟到了程序运行时,所以每次执行程序都需要进行链接,所以性能会有一定损失。

这个过程将x.o文件转化成可执行的文件