《程序是怎样跑起来的》(上)

学习笔记

此书前言

无论任何事情,了解其本质非常重要。只有了解了本质才能提高利用效率。这样一来,即使有新技术出现,也能很容易的理解并掌握。

第1章 对程序员来说CPU是什么

本章提问

  1. 程序是什么?
  2. 程序是由什么组成的?
  3. 什么是机器语言?
  4. 正在运行的程序存储在什么位置?
  5. 什么是内存地址?
  6. 计算机的构成元件中,负责程序的解释和运行的是哪一个?

本章重点

重点要理解寄存器

1.1 CPU内部结构解析

一、先看程序运行的一般流程:一般流程
这个图可能只是在说编译型语言吧。
在程序运行过程中,CPU负责解释和运行最终转换成机器语言的程序内容
二、CPU的组成

  • CPU是由寄存器、控制器、运算器、时钟组成的;
  • 寄存器用来暂时存储指令、数据等对象,一个CPU可能会有20~100个寄存器;
  • 控制器负责把内存上的指令和数据读入寄存器,并根据运算结果来控制计算机;
  • 运算器负责运算被读入寄存器的内容;
  • 时钟负责发出CPU开始计时的信号。

CPU组成
三、内存
通常说的内存指计算机的主存储器,其中的数据会随关机而清除。


##1.2 CPU是寄存器的集合体 程序员需要重点关注寄存器,其它的了解即可,因为**```程序是把寄存器作为对象来描述的```**。 使用高级语言编译后会转化成机器语言,然后再通过CPU内部的寄存器来处理。 通过阅读汇编语言的代码,可以了解转化成机器语言的程序运行情况。 汇编语言为每一个机器语言指令添加一个助记符,汇编语言与机器语言是一一对应的。将汇编语言转化为机器语言称为汇编,反之称为反汇编。 下面是一个汇编语言示例:![汇编语言示例](https://upload-images.jianshu.io/upload_images/17108100-790a92316b64450b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 其中,add(相加)与mov(存储,move)都是助记符,eax和ebp都是寄存器。 从示例中可以看出,机器语言级别的程序是通过**```寄存器```**来处理的。 我们可以将寄存器大致分为8类,用于运算的数值放在累加寄存器中存储,表示内存的数值放在基址寄存器和变址寄存器中存储,上面的eax和ebp分别是累加寄存器和基址寄存器。 ![寄存器大致分类](https://upload-images.jianshu.io/upload_images/17108100-98ce8e25a326b32f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 对程序员来说,CPU就是具有各种功能的寄存器的集合体。 ![](https://upload-images.jianshu.io/upload_images/17108100-d67ed2b8b002328a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##1.3 决定程序流程的程序计数器 下图中的流程计算123+456:![流程](https://upload-images.jianshu.io/upload_images/17108100-04983d6329e1b704.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 一个命令或一个数据通常被存储在多个地址上,为了便于说明,图中将其都分配到了一个地址中。 1. 操作系统把程序复制到内存; 2. 程序运行,没运行一步,程序计数器加一; 3. 控制器根据程序计数器的数值,从内存读取命令并执行。

总而言之,程序计数器决定程序的流程。


##1.4 条件分支和循环机制 程序的流程分为**```顺序```、```条件分支```、```循环```**三种。 下面的图很清楚的讲述了条件分支时的程序计数器依靠跳转指令(jump)运作: ![条件分支示例](https://upload-images.jianshu.io/upload_images/17108100-5311148a77d684ce.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) **关于标志寄存器:** 标志寄存器负责保存运算结果的正、负、零,还有溢出、奇偶校验的结果。正、负、零三种状态保存寄存器的三个位,根据数据状态把相应位置为1。![标志寄存器的三个位](https://upload-images.jianshu.io/upload_images/17108100-9841e10067060ee7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) **关于比较运算:** 实际上是把要比较的两个数相减后把结果的状态保存到标志寄存器中。
##1.5 函数的调用机制 依靠call、return指令和栈实现调用函数的下一行指令的返回。 1. 调用函数时,call会把调用函数后要执行的指令存储在名为栈的主存内; 2. 函数执行完毕后,再用return把栈中的地址设定到程序计数器中实现返回。 ![](https://upload-images.jianshu.io/upload_images/17108100-d4c7a1e8786246b2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ![函数调用中程序计数器和栈的职责](https://upload-images.jianshu.io/upload_images/17108100-5e308cf741e698e2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##1.6 通过地址和索引实现数组 实现数组要依靠基址寄存器和变址寄存器。基址寄存器不变,改变变址寄存器,变址寄存器的值就相当于数组的索引。 ![地址与索引](https://upload-images.jianshu.io/upload_images/17108100-0eaad2aa4aa584cf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##1.7 CPU的处理其实很简单 虽然程序很复杂,但是CPU执行的机器语言指令种类是比较少的,下图对指令进行了大体分类:![大体分类](https://upload-images.jianshu.io/upload_images/17108100-3e1aac92220704ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
#### 问题答案: >1. 一般所说的程序,指的是行事的先后顺序,计算机程序与之类似,指的是指示计算机每一步动作的一组指令; >2. 指令和数据。程序是指令和数据的组合体。如print("Hello"),print是指令,Hello是数据。 >3. CPU可以直接识别并使用的语言; >4. 内存,硬盘等媒介保存的程序需要复制到内存后才能运行; >5. 内存中,用来表示指令和数据存储位置的数值; >6. CPU.
# 第2章 数据是用二进制数表示的 #### 本章提问 >1. 32位是几个几个字节? >2. 二进制数01011100转换成十进制数是多少? >3. 二进制数00001111左移两位后,会变成原数的几倍? >4. 补码形式表示的8位二进制数11111111,用十进制数表示的话是多少? >5. 补码形式表示的8位二进制数10101010,用16位的二进制数表示的话是多少? >6. 反转部分图形模式时,使用的是什么逻辑运算? #### 本章重点 二进制及其运算
##2.1 用二进制数表示计算机信息的原因 计算机内部的电子元件是由IC(Integrated Circuit,集成电路)构成的,CPU也不例外。IC的的旁边有引脚,有电流通过时,表示1,反之表示0。 ![引脚](https://upload-images.jianshu.io/upload_images/17108100-08d9a9c98884eb5d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 其中一个引脚表示一位(bit, 即binary digit),8位表示一个字节,**```内存和磁盘都是用字节单位储存和读写数据,因此,字节是信息的基本单位。```**32位处理器,即表示一次可以处理32位(4字节)的二进制信息。 > 对于用二进制表示的信息,计算机不会区分它是数值、文字,还是某种图片的模式等,而是根据编写程序的各位对计算机发出的指示来进行信息的处理。


##2.2 什么是二进制数 各种进制的转换。
##2.3 移位运算和乘除运算的关系 ![左移两位的运算](https://upload-images.jianshu.io/upload_images/17108100-a83f4c65f5d86c5b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 左移运算需要在空出来的低位补0,右移运算在后面说明。另外,移位导致溢出的数字,直接丢弃即可。 可以依靠移位运算来进行乘除运算,二进制左移后会变为原来的二倍、四倍等等,右移会变为二分之一、四分之一等等。
##2.4 便于计算机处理的补数 将所有的位取反再加一就得到补数,数及其补数互为相反数。 ![得到补数](https://upload-images.jianshu.io/upload_images/17108100-1a0a10224292a5ee.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 为什么数与其补数互为相反数? ![](https://upload-images.jianshu.io/upload_images/17108100-4feb40eb582d7a25.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 计算机用加法实现减法运算,减某数就等于加上某数的补数。 ![3-5的运算结果](https://upload-images.jianshu.io/upload_images/17108100-f8f179e424ae0ff4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##2.5 逻辑右移和算术右移的区别 **什么是逻辑右移?** > 当二进制数的值表示图形模式而非数值时,移位后需要在最高位补0.类似于霓虹灯往右滚动的效果。 ![逻辑右移](https://upload-images.jianshu.io/upload_images/17108100-1dedec9e8a23c95f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

什么是算术右移?

当二进制数作为带符号的数值进行运算时,移位后要在最高位填充移位前符号位的值(0或1),这就叫算术右移。

只有在右移时才必须区分逻辑右移和算术右移的区别。左移时,只需要在空出来的低位补0即可。
逻辑右移与算术右移的区别

符号填充:
符号填充


##2.6掌握逻辑运算的窍门 4种类型:逻辑非、逻辑或、逻辑与、逻辑异或。 ![](https://upload-images.jianshu.io/upload_images/17108100-6a17166beb9d2ae2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
####答案: >1. 4 >2. 92 >3. 4倍 >4. -1 >5. 1111111110101010 >6. 异或
# 第3章 计算机进行小数运算时出错的原因 #### 本章提问 ![问题](https://upload-images.jianshu.io/upload_images/17108100-5add9ad972aa59c6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ####本章重点 计算机进行小数处理的机制 ##3.1 将0.1累加100次也得不到10 ![将0.1累加100次(C语言)](https://upload-images.jianshu.io/upload_images/17108100-29f63826c7d3522e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ![结果](https://upload-images.jianshu.io/upload_images/17108100-fdedf726dd1c305b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##3.2 用二进制数表示小数 就是用负数来表示相应位数的指数 ![二进制小数转十进制](https://upload-images.jianshu.io/upload_images/17108100-2bd4e5a03d8ee8fc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##3.3 计算机运算出错的原因 如图:![](https://upload-images.jianshu.io/upload_images/17108100-8f23ce90b9e8aa65.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 二进制小数无法连贯的表示十进制小数
##3.4 什么是浮点数 浮点数的形式:![](https://upload-images.jianshu.io/upload_images/17108100-169010ce63b43051.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 浮点数由**```符号、尾数、基数、指数```**四部分构成。 浮点数的构造(IEEE的规定):![](https://upload-images.jianshu.io/upload_images/17108100-deb02ff1e2c1c00f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 其中,符号部分非0即1;尾数部分用的是“将小数点的前面的值固定为1的正则表达式”,指数部分用“EXCESS系统表现”。简单的来说,小数就是**```尾数部分×2的指数部分次幂```**。 PS,正则表达式是**按照特定的规则来表示数据的形式**。
##3.5 正则表达式和EXCESS系统 ####尾数部分是如何用正则表达式来表示的呢? 先看十进制。比如十进制数0.75,可以用很多种方法来表示它,正如下图所示。由于方法太多,需要制定一个统一的规则方便计算机处理,比如可以规定十进制小数“小数点前面是0,小数点后面第一位不能是0”。 ![数值的多种表现形式](https://upload-images.jianshu.io/upload_images/17108100-b07944dc8178cc31.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 同样的,我们也可以为二进制指定规则。在二进制中,我们使用的是“将小数点前面固定为1”的正则表达式(个人理解:由于二进制只由0、1组成,如此做就相当于在小数点前保留1位有效数字)。这样的话,第一位中的1可以不去保存,因为怎么样都是1,这样就节省了一个数据位,也就可以表示更大范围的数据。![](https://upload-images.jianshu.io/upload_images/17108100-99490ae7dd9cdd5c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 如果第1位始终是1,那么0怎么表示呢?查了[资料](http://www.cnblogs.com/german-iris/p/5759557.html),当尾数和指数均为0时,表示0,那1又怎么表示呢...........暂时还没有找到资料,知道的大佬可以告诉我下。 ####指数部分与EXCESS系统 就是把中间的数当成0来看。 ![EXCESS](https://upload-images.jianshu.io/upload_images/17108100-e827feeca42766ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##3.6 在实际的程序中进行确认 ![代码第一部分](https://upload-images.jianshu.io/upload_images/17108100-b77c64cb41ad78be.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ![代码第二部分](https://upload-images.jianshu.io/upload_images/17108100-2a0d2815b320aebc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 说下我的理解,memcpy就相当于把data内存中由0、1组成的序列复制到buff中去,但是程序中buff的值是用十进制显式表示的,所以需要不停对2取余获得真实的二进制序列。 程序结果及解释: ![](https://upload-images.jianshu.io/upload_images/17108100-91c12099aca22a17.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##3.7 如何避免计算机计算出错 1. 回避策略,即无视错误,一点微小的偏差不会造成什么严重后果; 2. 扩大相应的倍数用整数进行运算; 3. 采用BCD方法。(暂时不太懂)
##3.8 二进制数和十六进制数 二进制的4位等于十六进制的1位。 ![](https://upload-images.jianshu.io/upload_images/17108100-323c0c1eac07a36b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ![](https://upload-images.jianshu.io/upload_images/17108100-849f5226b97ba2fc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
####问题答案:![](https://upload-images.jianshu.io/upload_images/17108100-77136ea77c38f76c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
####[《程序是怎样跑起来的》 (中)](https://www.cnblogs.com/xmusxy/p/10914345.html)
posted @ 2019-05-23 20:32  深夜饿狗  阅读(450)  评论(0编辑  收藏  举报