想知道你写的C语言代码如何运行的吗?看这里!!!

C语言编译连接----幕后小故事

咱们在计算机中写的.c文件,被称为C语言源代码,这种源代码机器是不认识的,为了让机器认识C语言源代码,那么必需要通过这么几个过程(预处理、编译、汇编、连接、加载),让源代码变为机器语言的目标文件,才能够变为可执行程序。html

下图为编译过程:

预处理器
编译器
汇编器
连接器
加载器
源代码
扩展的源代码
汇编源代码
目标代码
可执行代码
可执行文件

讲解上图:

这里的源代码姑且叫它sample.c,将它通过预处理器;node

  • 预处理器(预处理)的描述: 预处理器对源代码进行宏替换、条件编译、展开头文件、去掉注释、处理特殊符号操做;产生扩展源代码sample.i;
  • 编译器(编译): 编译器对sample.i进行语法和词法的分析以及代码的优化处理,在确认全部的语法符合C语言规则后,将sample.i转化为等价的中间源代码或汇编源代码sample.s
  • 汇编器(汇编): 汇编器对sample.s进行汇编,汇编就是将汇编源代码转化为目标代码sample.o也就是二进制文件;
  • 连接器(连接): 有将sample.o文件转换为了sample.exe文件些人会提出疑问,在汇编阶段不是已经产生了二进制代码文件了吗?机器不是能够识别二进制代码文件吗?为何还要进行下一步的连接处理呢?
    答:由汇编程序生成的目标文件并不能当即就被执行,其中可能还有许多没有解决的问题。
      例如,某个源文件中的函数可能引用了另外一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。全部的这些问题,都须要经连接程序的处理方能得以解决。
    连接程序的主要工做就是将有关的目标文件彼此相链接,也即将在一个文件中引用的符号同该符号在另一个文件中的定义链接起来,使得全部的这些目标文件成为一个可以诶操做系统装入执行的统一总体。

根据开发人员指定的同库函数的连接方式的不一样,连接处理可分为两种:web

(1)静态连接
  在这种连接方式下,函数的代码将从其所在地静态连接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态连接库其实是一个目标文件的集合,其中的每一个文件含有库中的一个或者一组相关函数的代码。编程

(2) 动态连接
  在此种方式下,函数的代码被放到称做是动态连接库或共享对象的某个目标文件中。连接程序此时所做的只是在最终的可执行程序中记录下共享对象的名字以及其它少许的登记信息。在此可执行文件被执行时,动态连接库的所有内容将被映射到运行时相应进程的虚地址空间。动态连接程序将根据可执行程序中记录的信息找到相应的函数代码。编辑器

  • 加载器(加载): 每当咱们给出执行特定程序的命令时,加载器就会开始工做。加载程序将.exe文件加载到RAM中,并通知CPU加载此程序的地址的起始点,就能够开始运行程序。

连接器与加载器的区别:svg

连接器 加载器
连接器生成源程序的可执行模块 加载器将可执行模块加载到主存储器以供执行
连接器将汇编程序生成的目标代码做为输入 加载器将连接器生成的可执行模块做为输入
连接器组合源代码的全部对象模块以生成可执行模块 加载器将地址分配给主存储器中的可执行模块以供执行
连接器的类型是连接编辑器,动态连接器 加载器的类型是绝对加载,可重定位加载和动态运行时加载