代码从 “ctrl+F5” 到 “屏幕输出” 所经历的过程详解——翻译环境(编译+链接)+ 执行环境

前言

我们用编译器写完代码后,只需Crtl+F5即可让代码跑起来,最后将结果输出到屏幕上,那么你知道在这个过程中都经过了哪些步骤吗?

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

我们运行代码时都将经历这两个过程,最后才将运行结果呈现在屏幕上。
在这里插入图片描述

翻译环境

在翻译环境下,要经历两个过程,即编译链接。我们写的程序中可能包含多个源文件(以.c为后缀),编译过程中这些源文件会单独经过编译器处理,最后生成对应的目标文件(以.obj为后缀),而在链接过程中,链接器会把这些目标文件和链接库(存放的是库函数信息)链接起来,最后生成可执行程序。
在这里插入图片描述
总结:

  • 组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code)。
  • 每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序。
  • 链接器同时也会引入标准C库函数中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。

例如,我们写一个简单的加法函数在源文件Add.c中,再写一个源文件test.c用于调用Add函数,当程序执行完毕后,我们可以在文件中找到这些文件:
在这里插入图片描述

接下来,我们再深入认识一下编译和链接中每一步具体干了些什么事。

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

编译过程其实又被细分为三个环节,即预编译,编译和汇编。
一、预编译
在预编译这个环节,编译器主要会对C代码做这三件事:

  1. 头文件的包含。 在预编译阶段,编译器会将代码中所包含的头文件都替换成头文件的内容。例如,#include <stdio.h>这句代码会被替换成stdio.h这个头文件中的全部代码。
  2. 注释的删除。 在预编译阶段,编译器会将代码中所有的注释都删去,这样可以减少代码量,毕竟运行代码的时候编译器也不用看你的注释。
  3. #define定义的符号的替换。 我们都知道#define定义的标识符也好,定义的宏也罢,都是起到替换的作用,而真正进行替换的时刻便是预编译阶段。

二、编译
编译阶段的主要任务就是将C代码翻译成汇编指令,这个过程主要包括这四个步骤:

  1. 词法分析。 词法分析的任务是对由字符组成的单词进行处理,从左至右逐个字符地对源程序进行扫描,产生一个个的单词符号,把作为字符串的源程序改造成为单词符号串的中间程序。
  2. 语法分析。 编译程序的语法分析器以单词符号作为输入,分析单词符号串是否形成符合语法规则的语法单位,如表达式、赋值、循环等,最后看是否构成一个符合要求的程序,按该语言使用的语法规则分析检查每条语句是否有正确的逻辑结构,程序是最终的一个语法单位。
  3. 语义分析。 语义分析是编译过程的一个逻辑阶段, 语义分析的任务是对结构上正确的源程序进行上下文有关性质的审查,进行类型审查。语义分析是审查源程序有无语义错误,为代码生成阶段收集类型信息。
  4. 符号汇总。 在这个环节中,会将每个源文件的全局范围的变量符号进行汇总。
    在这里插入图片描述

三、汇编
汇编的时候会将汇编指令转换成二进制指令存放在相应的文件中(.obj为后缀),同时会给每个源文件汇总出来的符号分配一个地址,然后分别生成一个符号表。
在这里插入图片描述
注:因为test.c文件中提取的符号Add只是Add函数的声明,并不是定义,无法判断Add函数是否真正存在,所以test.c生成符号表时分配给Add符号的地址是一个无意义(非法)的地址。

链接

在链接过程中,编译器主要完成以下两个任务:

  1. 合并段表。 其实,汇编结束后所生成的obj文件内部会被划分为几个段,在链接过程中就会把每个obj文件对应的段通过某种规则合并起来,最后形成可执行程序(.exe为后缀)。
    在这里插入图片描述

  2. 符号表的合并和重定位。 在链接期间会将每个源文件的符号表进行合并,若不同源文件的符号表中出现了相同的符号,则取合法的地址为合并后的地址(重定位)。
    在这里插入图片描述
    注:符号表并非无意义。例如,当要调用某一函数时,编译器会在符号表中查找该符号,若有,则调用成功,否则调用失败。

执行环境

exe程序执行的过程大概可以分为四个步骤:

  1. 程序首先要载入内存中。 在有操作系统的环境中,该操作一般由操作系统来完成。在独立的环境中,程序的载入可以由手工完成,也可以通过可执行代码置入只读内存来完成。
  2. 程序的执行开始。 接着便调用main函数。
  3. 开始执行程序代码。 这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留它们的值。
  4. 终止程序。 正常终止main函数,也可能是以外终止。
  • 19
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
一、实验目的 1、了解虚拟存储器的基本原理和实现方法。 2、掌握几种页面置换算法。 二、实验内容 设计模拟实现采用不同内外存调度算法进行页面置换,并计算缺页率。 三、实验原理 内存在计算机中的作用很大,电脑中所有运行的程序都需要经过内存来执行,如果执行的程序很大或很多,就会导致内存消耗殆尽。为了解决这个问题,Window中运用了虚拟内存技术,即拿出一部分硬盘空间来充当内存使用,当内存占用完时,电脑就会自动调用硬盘来充当内存,以缓解内存的紧张。 虚拟存储器是指具有请求调入功能和置换功能,能从逻辑上对内存容量加以扩充的一种存储器系统。它是采用一定的方法将一定的外存容量模拟成内存,同时对程序进出内存的方式进行管理,从而得到一个比实际内存容量大得多的内存空间,使得程序的运行不受内存大小的限制。虚拟存储区的容量与物理主存大小无关,而受限于计算机的地址结构和可用磁盘容量。 虚拟内存的设置主要有两点,即内存大小和分页位置,内存大小就是设置虚拟内存最小为多少和最大为多少;而分页位置则是设置虚拟内存应使用那个分区中的硬盘空间。 1. 最佳置换算法(OPT):选择永不使用或是在最长时间内不再被访问(即距现在最长时间才会被访问)的页面淘汰出内存。 2. 先进先出置换算法(FIFO):选择最先进入内存即在内存驻留时间最久的页面换出到外存。 3. 最近最久未使用置换算法(LRU): 以“最近的过去”作为“最近的将来”的近似,选择最近一段时间最长时间未被访问的页面淘汰出内存

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

2021dragon

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

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

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

打赏作者

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

抵扣说明:

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

余额充值