C语言程序生命周期

可能大家都知道一个C语言程序需要经过编译生成可执行文件就可以运行起来,但是这并非是一个完整的C语言程序流程,下面我们就详细了解一下C语言程序的整个生命周期。

一个完整C语言的生命周期分为以下五个部分:

  • 编写代码
  • 编译
  • 链接
  • 装载
  • 执行

1. 编写代码

编写代码是大家最熟悉不过的了,相信大家在学校里学C语言的第一步都是输出"Hello World",也就是编写代码这一步。如果大家使用的开发环境是Visual Studio等IDE的话,直接点个运行,程序的结果就输出在你面前了。如果不详细追究过程,可能连编译是什么都不知道(初学C语言时的我就是这样的),以为编写的代码本来就是可以直接运行的,这是因为IDE(集成开发环境)把编译、链接、装载、执行都集成到运行按钮上了,IDE可以简化开发流程,对新手比较友好,但是不利于我们理解C语言程序生命周期。下面我们就详细了解一下编译、链接、装载、执行这些步骤。

2. 编译

大家都知道计算机只能识别0和1,所以编译就是将高级语言写的代码转换成计算机能够识别的二进制即0和1,如果在学习C语言的时候用的是Linux操作系统,那么应该了解编译这一过程,比如使用命令gcc main.c -o main即可将一个名为main.c的程序编译为名为main.o的二进制可执行文件。

上述命令中的gcc为C语言编译器,编译器负责编译程序。除gcc编译器以外还有许多编译器,比如负责交叉编译的gcc-arm,clang等编译器。

编译器的输入是程序源文件,比如上述命令中的main.c就是一个C语言源文件。同时编译器可以有多个输入,比如下列命令gcc main.c function.c -o main,可以将多个有关联的文件组合为一个main.o程序。当然通常情况下,不会这么编译程序,而是借助makefile。

编译器的输出是所有二进制目标文件的集合,每一个目标文件对应一个输入文件,最后为了让程序运行起来,还需要经过链接这一过程,即将所有目标文件组合为一个可执行文件的过程。

编译分为如下4个步骤:详细过程可以参考我之前写的帖子认识GCC_CyberMakes的博客-CSDN博客

a. 预处理(Preprocessing):对每个源文件进行预处理,包括宏展开、头文件包含、条件编译等。预处理的输出是扩展后的源文件。

b. 编译(Compiling):将预处理后的源文件编译成汇编代码。编译器将源代码转换为特定机器架构的汇编语言。

c. 汇编(Assembling):将汇编代码转换为机器代码,生成目标文件。汇编器将汇编语言转换为机器指令和数据。

d. 链接(Linking):链接器将所有的目标文件和库文件合并,生成最终的可执行文件。

其实链接也是编译的一部分,但是需要单独看一下,因为链接过程比较重要。

3. 链接

链接是将多个目标文件和库文件组合成一个可执行文件或者共享库的过程。链接器将目标代码与所需的库函数和其他目标文件进行组合,生成最终的可执行文件。链接分为静态链接和动态链接两种类型,动态库和静态库也是两个比较重要的概念。

静态链接和动态链接的区别:静态链接将所有需要的头文件都放到编译出来的二进制文件中。动态链接将不会链接一些不必要的库,直到程序运行时进行链接。

  1. 符号解析(Symbol resolution):链接器解析目标文件中使用的符号,包括函数、变量等。对于未定义的符号,链接器会在其他目标文件和库文件中查找定义。

  2. 重定位(Relocation):在符号解析之后,链接器需要确定每个符号在最终可执行文件中的地址。它会将每个符号的引用替换为对应的地址。

  3. 符号表生成(Symbol table generation):链接器生成一个符号表,记录所有的符号及其对应的地址。这个符号表在程序执行时,可用于动态链接、调试等。

  4. 地址解析(Address resolution):如果目标文件或库文件中有引用其他库的符号,链接器会解析这些引用,并将它们与相应的库文件关联起来。

  5. 可执行文件生成(Executable file generation):最后,链接器将经过重定位和符号解析后的目标文件和库文件合并成一个可执行文件。这个可执行文件包含了所有需要的代码和数据,可以直接执行。

链接是一个非常复杂的过程,具体推荐大家去看一下程序员的自我修养这本书。
链接的最终结果就是二进制可执行文件,其结构遵循目标平台的二进制可执行文件格式,Linux系统下的二进制可执行文件格式为ELF格式。虽然不同平台下的格式不同,但本质上可执行文件会包含.text .bss .data等由链接器链接起来的各种节。

4. 装载

装载器最重要的最用就是把链接器链接好的节复制到进程内存映射中

5. 执行

一开始我们会认为一个C/C++程序是从main函数开始执行的,但在main函数之前还会执行一些其他函数,这些函数用于为运行程序做准备。装载器装载程序后会执行一段汇编代码,初始化堆栈寄存器、PC基准其等一系列寄存器后调用main函数开始真正意义上的执行程序。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

指针到处飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值