分享

乐创DIY C语言讲义​——1.3节

 乐创客搬运工 2021-01-27

1.3 软件的具体执行

在学习C语言之前,了解计算机硬件如何执行软件是一件非常必须的事情,一个优秀的程序员,必定会对计算机硬件有很深的认识。

首先先思考一个问题,软件究竟是什么?其实软件用最简单的话语描述出来就是指挥计算机去做特定的事情,这就类比于你老妈让你出去遛弯的时候买一瓶酱油回来,如果途中看到有卖西瓜的就买一个西瓜来。对于上述这个段子,“老妈”这个角色就类比于决策者(程序员),“你”这个角色就类比于执行者(计算机)。但是“你”和“你老妈”与“程序员”和“计算机”这两组对象之间最大的不同是,“你”和“你老妈”是有直接的语言沟通的,而“程序员”和“计算机”之间是没有直接可以沟通的语言的。计算机知道什么语言?之前我们简单地说过,计算机只懂那一串串的二进制机器语言,不懂这些26个字母。

假定大家都有一定的数字电路基础,我们先来看一下一个数字电路模型框框图1-3-1加法器框图所示。

图1-3-1 加法器框图

图1-3-1中,寄存器A和B中存放着需要进行加法操作的两个加数,寄存器外面都直接连接一个门控芯片,门控芯片的门控信号由译码器电路所控制。同时想要实现加法操作的话,也需要加法器的选通信号有效,一旦当这些选通信号都满足条件,那么就能实现一个功能,即将寄存器A和寄存器B里面的内容相加,相加的结果送入暂存器里面。这就是这个框图想要表达的意思。然而这和计算机有什么关系呢?大家不妨可以发散地思考下,所谓的计算机,不就是完成算数和逻辑运算的机器吗?只不过其内部有无数个算术加法模块,还有可能有无数个用于与或非计算的逻辑运算模块。再大胆点可以想一下,我上图中所描述了加法器选通信号,那么是否会有乘法器选通信号,移位器选通信号?这样的话,我们就可以对这个核心部件进行扩充了,如图1-3-2所示。

图1-3-2 中央处理器内部指令集

从图1-3-2中我们可以看出,每个指令其实对应的就是CPU的一个功能,这个功能是一个CPU最量子化的东西,即一条指令必定会对应于一条功能。从图中我们再联想下,假设一个CPU具有20条指令,那么选通它们的信号线就要有20条,而计算机是一个被编码的东西,因此这些指令都需要被编码,就假设一个计算机有20条指令,那么用二进制编码的话至少需要5根线(2^5=32),即假设“00000b”表示加法,“00001b”移位……。同样的,前面所述的那些寄存器,它们其实也都有一个固定的地址。在CPU内部,那些用于执行具体算术或者逻辑运算指令功能的部件被称为“算术逻辑单元”或者“ALU”。

以X86架构的计算机为例一个程序被编译并且部署(存放到计算机上)好之后,其所存在的位置一定是硬盘或者Flash等非易失性存储器,这种存储器的读写速度往往非常慢,一旦程序需要被执行,计算机首先会把整个程序的执行代码搬到内存上面,这个时候程序的存取速度就提高了一个档次。以PC为例,内存一般是SDRAM(synchronous dynamic random-access memory,同步动态随取存取存储器),它提供给用户的只是一些地址线(不是简单的地址线,这里不做赘述),控制线和数据线。那么问题来了,计算机在需要取指令的时候是如何实现的呢?

说到这里,需要先来讲述一下冯·诺依曼结构,这种结构当然是由伟大的数学家冯·诺依曼提出的计算机模型,它大致包含如下几点主要内容:

(1)采用存储程序方式,指令和数据不加区别混合存储在同一个存储器中,数据和程序在内存中是没有区别的,它们都是内存中的数据,当EIP指针指向哪 CPU就加载那段内存中的数据, 指令和数据都可以送到运算器进行运算,即由指令组成的程序是可以修改的。

(2)存储器是按地址访问的线性编址的一维结构,每个单元的位数是固定的。

(3)指令由操作码和地址码组成。操作码指明本指令的操作类型,地址码指明操作数和地址。操作数本身无数据类型的标志,它的数据类型由操作码确定。

(4)通过执行指令直接发出控制信号控制计算机的操作。指令在存储器中按其执行顺序存放,由指令计数器指明要执行的指令所在的单元地址。指令计数器只有一个,一般按顺序递增,但执行顺序可按运算结果或当时的外界条件而改变。

(5)以运算器为中心,I/O设备与存储器间的数据传送都要经过运算器。

(6)数据以二进制表示。

这里的第一点比较重要,如图1-3-3所示。假设在一台不考虑操作系统的X86计算机上面有一块完整的内存,当一个程序被运行时,它会被计算机从硬盘中取出,按照代码段,数据段,堆栈段,扩展段等形式随机地被放到内存上面,并且将代码段的基地址(起始地址)传给CPU的CS(代码段寄存器),CPU内部有一个指令指针EIP,指令指针EIP寄存器包含了当前代码段中的一个偏移量,通过CS:EIP联合指向了即将执行的下一条指令。同理,数据在被搬到内存上的时候是放在数据段里面的,数据段的基址会被传给CPU 的DS(数据段寄存器),当指令里面指定了某一个特定的地址时,就会根据这个数据段的基址和偏移量计算出具体的物理内存地址,进行数据的存储。举一个容易理解的例子,比如住酒店时,假设你定的房间号是3230,前台给你房卡的时候跟你约定好了前面两位代表的是楼号,后面两位代表的是房号,那你找房间时肯定先找楼层32,找到楼层后再找房号30,那对应计算机里寻址,这个楼层就相当于基址,房号相当于偏移量。

关于这个基地址和偏移量如何计算的问题,大家有兴趣可以详细地去学习一下“微机原理”。计算机在需要取指令的时候是如何实现?这个问题我想大家已经有了答案,其实X86CPU内部有一个专门用作地址译码的单元,就做“总线接口部件”(BIU)。

图1-3-3 冯诺依曼结构内存示意

以上是冯·诺伊曼结构的简单介绍,类似的,还有一种架构天然地就把程序代码段和数据段完全独立地放置到了两个独立的存储器上,这种架构叫做“哈佛”架构,一般多见于嵌入式处理器上面。

+++++++++++++++++++好书推荐++++++++++++++++++

推荐理由:微机原理40多年的发展,到现在还在沿用X86架构,这本书中的内容非常详细,深入浅出

适应人群

          1、软件开发人员的理论加深;

           2、计算机从业人员;

          3、爱学习的童鞋。

推荐指数:

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多