当前位置:网站首页>详解程序执行过程

详解程序执行过程

2022-08-11 05:30:00 CHAKMING1

目录

前言

翻译环境

编译=预编译+编译+汇编

一、预编译

二、编译

三、汇编

链接

 执行环境


前言

每次用编译器写完一个程序后,我们会进行调试和执行,将代码的结果输出在我们的电脑屏幕上,但是我们并不清楚,为什么我们写的这些代码,可以转为我们想要的结果呢?

其实,在ANSI C(标准C) 的任何一种实现中,都存在两个不同的环境,即翻译环境执行环境。翻译环境内,代码被转换为可执行的机器指令。执行环境内,它用于实际执行的代码。

那么,我们的程序就是进行了这两个过程,才最终将我们想要的结果输出在屏幕上。

翻译环境

翻译环境下,程序会经过两个阶段,一个是编译,一个是链接。在一个工程里面,我们可能会有多个不同的源文件(.c后缀),那么这些源文件会通过编译器进行单独处理,会生成对应的目标文件(.obj后缀),而再经过链接之后,链接器会把这些目标文件和链接库连接起来。生成可执行程序(.exe后缀)。

通过上图我们可以看到,每个源文件都是经过编译器会生成一个对应的目标文件,转换成为对应的目标代码。然后再由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序。链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且也会搜索程序员个人的程序库,将需要的函数链接到程序中。

编译=预编译+编译+汇编

编译过程在细分下来可以分为三个环节,预编译、编译和汇编

一、预编译

在预编译这个阶段,编译器会进行的三个主要操作:

  1. 头文件的包含。在预编译阶段,编译器会将代码所包含的头文件替换成头文件的内容。通常,我们的代码会加上#include <stdio.h>这个头文件,这是在预编译的时候,就会去引用这个头文件的所有内容。
  2. #define 定义的符号替换。我们通常使用define定义标识符和宏。假设,我们这里顶一个一个MAX为100,#define MAX 100 ,那么在预编译阶段,我们程序中的MAX会被直接替换成100。
  3. 注释的删除。要知道一段程序中的注释通常是程序员在写代码过程中对代码的解释,这些解释对于程序来说是没有影响的。所以会在预编译这个阶段,将代码的注释进行删除

二、编译

编译阶段,最终是为了将C代码翻译成汇编代码,过程比较复杂,主要包括四个步骤:

  1. 词法分析。这一过程是将字符序列转为单词序列。这里的单词是一个字符串,是构成源代码的最小单位。从输入字符流中生成单词的过程叫作单词化,同时会对单词进行分类。比如:sum = 2+3; 将会拆成sum、=、2、+、3 这些单词。
  2. 语法分析。这一过程是分析单词符号串是否形成符合语法规则的语法单位。如表达式、赋值、循环等,最终是否构成一个符合要求的程序,再按照对应语言的语法规则检查每条语句是否正确。
  3. 语义分析。语义分析是对结构上正确的源程序进行上下文有关性质的审查,进行类型审查。比如语义分析的一个工作是进行类型审查,审查每个运算符是否具有语言规范允许的运算对象,当不符合语言规范时,编译程序 应报告错误。
  4. 符号汇总。这个环节会将源文件的全局函数的函数名进行汇总。

三、汇编

这一步是将汇编指令转换成二进制指令存放在一个obj后缀的目标文件中,同时会给每个源文件汇总出来的符号分配一个地址,然后生成一个符号表。

链接

在链接阶段,编译器主要完成两个任务:

  1. 合并段表。在汇编结束生成的obj文件,内部其实会被划分为几个段,在链接过程中会将这些段进行合并。
  2. 符合表的合并和重定位。在链接过程中,我们会对不同的符合分配一个相应的地址。而有的时候,一些符号在它所处的文件中并不存在,存在于另一个文件中,这时候我们会提前分配一个无意义的地址。在合并之后,会将合法的地址重新定位覆盖原来无意义的地址。

 执行环境

程序执行的过程:

  1. 程序载入内存。一般这是由操作系统进行。在独立的环境中,程序的载入手动安排,也可以通过可执行代码置入只读内存来完成。
  2. 程序的执行是由main函数开始。
  3. 开始执行程序代码,使用一个运行时堆栈,存储函数的局部变量和返回地址,同时在静态区存储静态变量,直到程序结束。
  4. 终止程序。main函数结束或者意外结束。
原网站

版权声明
本文为[CHAKMING1]所创,转载请带上原文链接,感谢
https://blog.csdn.net/CHAKMING1/article/details/124064570