Skip to content

程序是怎样跑起来的

[!abstract] 程序是怎样跑起来的

  •  程序是怎样跑起来的|200
  • 书名: 程序是怎样跑起来的
  • 作者: 矢泽久雄
  • 简介: 日文版重印41次,“计算机组成原理”图解趣味版,蹲马桶就能看懂的编程基础知识!本书适合:菜鸟程序员入门进阶;中级程序员查漏补缺;高手程序员向家人(女友、老妈等)普及计算机知识。如何向小学生讲解CPU和二进制?如何向中学生讲解内存和磁盘?如何向女高中生讲解操作系统的原理?如何向老奶奶说明显示器和电视的不同?如果你完全没有思路,就应该读一读这本书。以图配文,深入讲解编程基础知识;语言通俗,即使是文科生也能看得懂。
  • 出版时间 2015-04-01 00:00:00
  • ISBN: 9787115385130
  • 分类: 计算机-编程设计
  • 出版社: 人民邮电出版社

高亮划线

1.1 CPU的内部结构解析

  • 📌 CPU的内部由寄存器、控制器、运算器和时钟四个部分构成,各部分之间由电流信号相互连通。 ^907761-10-1198-1241

    • ⏱ 2023-01-19 16:28:19
  • 📌 寄存器可用来暂存指令、数据等处理对象,可以将其看作是内存的一种。根据种类的不同 ^907761-10-1260-1306

    • ⏱ 2023-01-19 16:34:18
  • 📌 程序启动后,根据时钟信号,控制器会从内存中读取指令和数据。通过对这些指令加以解释和运行,运算器就会对数据进行运算,控制器根据该运算结果来控制计算机。 ^907761-10-2436-2510

    • ⏱ 2023-01-19 16:30:51

1.2 CPU是寄存器的集合体

  • 📌 通常我们将汇编语言编写的程序转化成机器语言的过程称为汇编;反之,机器语言程序转化成汇编语言程序的过程则称为反汇编 ^907761-11-1239-1340

    • ⏱ 2023-01-19 16:32:49
  • 📌 寄存器中存储的内容既可以是指令也可以是数据。其中,数据分为“用于运算的数值”和“表示内存地址的数值”两种。数据种类不同,存储该数值的寄存器也不同。CPU中每个寄存器的功能都是不同的。用于运算的数值放在累加寄存器中存储,表示内存地址的数值则放在基址寄存器和变址寄存器中存储。代码清单1-1的程序中用到的eax和ebp分别是累加寄存器和基址寄存器。表1-1 寄存器的主要种类和功能[插图] ^907761-11-2806-3056

    • ⏱ 2023-01-19 16:41:23

1.3 决定程序流程的程序计数器

  • 📌 程序计数器决定着程序的流程。 ^907761-12-1421-1435
    • ⏱ 2023-01-20 23:31:04

1.4 条件分支和循环机制

  • 📌 但若程序中存在条件分支和循环,机器语言的指令就可以将程序计数器的值设定为任意地址(不是+1)。这样一来,程序便可以返回到上一个地址来重复执行同一个指令,或者跳转到任意地址。 ^907761-13-622-708

    • ⏱ 2023-01-20 23:32:09
  • 📌 无论当前累加寄存器的运算结果是负数、零还是正数,标志寄存器都会将其保存(也负责存放溢出和奇偶校验的结果)。 ^907761-13-1410-1686

    • ⏱ 2023-01-20 23:33:53

1.5 函数的调用机制

  • 📌 在编译高级编程语言的程序后,函数调用的处理会转换成call指令,函数结束的处理则会转换成return指令。这样一来,程序的运行也就变得非常流畅。 ^907761-14-2291-2363
    • ⏱ 2023-01-22 00:37:23

1.6 通过地址和索引实现数组

1.7 CPU的处理其实很简单

  • 📌 看完表后你会惊奇地发现,原来 CPU可以进行的处理非常少。虽然高级编程语言编写的程序看起来非常复杂,但CPU实际处理的事情就是这么简单。这样一来,大家是不是能够消除“计算机机制看起来很难”这个印象了呢? ^907761-16-571-672

    • ⏱ 2023-01-22 00:44:30
  • 📌 表1-2 机器语言指令的主要类型和功能① 外围设备指的是连接到计算机的键盘、鼠标、显示器、设备装置、打印机等。 ^907761-16-731-972

    • ⏱ 2023-01-22 00:46:27

2.3 移位运算和乘除运算的关系

  • 📌 十进制数左移后会变成原来的10倍、100倍、1000倍……同样,二进制数左移后就会变成原来的2倍、4倍、8倍……反之,二进制数右移后则会变成原来的1/2、1/4、1/8…… ^907761-20-2158-2244
    • ⏱ 2023-01-22 18:09:07

2.5 逻辑右移和算术右移的区别

  • 📌 不管是正数还是用补数表示的负数,都只需用符号位的值(0或者1)填充高位即可。这就是符号扩充的方法。 ^907761-22-1816-1865
    • ⏱ 2023-01-22 20:45:00

3.2 用二进制数表示小数

  • 📌 小数点后面部分的位权,第1位是2的-1次幂、第2位是2的-2次幂 ^907761-27-1192-1224
    • ⏱ 2023-01-23 09:43:00

3.3 计算机运算出错的原因

  • 📌 计算机之所以会出现运算错误,是因为“有一些十进制数的小数无法转换成二进制数”。 ^907761-28-492-531
    • ⏱ 2023-01-23 09:43:52

3.4 什么是浮点数

  • 📌 双精度浮点数类型用64位、单精度浮点数类型用32位来表示全体小数 ^907761-29-603-694
    • ⏱ 2023-01-23 09:52:36

3.8 二进制数和十六进制数

  • 📌 二进制数的4位,正好相当于十六进制数的1位。 ^907761-33-591-613
    • ⏱ 2023-01-23 17:08:20

4.1 内存的物理机制很简单

  • 📌 图4-1是内存IC(在这里假设它为RAM[插图])的引脚配置示例。虽然这是一个虚拟的内存IC,但它的引脚和实际的内存IC是一样的。VCC和GND是电源,A0~A9是地址信号的引脚,D0~D7是数据信号的引脚,RD和WR是控制信号的引脚。将电源连接到VCC和GND后,就可以给其他引脚传递比如0或者1这样的信号。大多数情况下,+ 5V的直流电压表示1,0V表示0。 ^907761-35-758-1111
    • ⏱ 2023-01-23 21:20:33

4.3 简单的指针

4.4 数组是高效使用内存的基础

  • 📌 由于在C语言中,数组的索引是从0开始的,因此,char g[100];表示的就是可以使用g[0]~g[99]这100个元素。 ^907761-38-923-985
    • ⏱ 2023-01-23 21:34:37

4.6 链表使元素的追加和删除更容易

  • 📌 接下来介绍的链表和二叉查找树,都是不用考虑索引的顺序就可以对数组元素进行读写的方式。通过使用链表,可以更加高效地对数组数据(元素)进行追加和删除处理。而通过使用二叉查找树,则可以更加高效地对数组数据进行检索。 ^907761-40-444-548
    • ⏱ 2023-01-23 21:43:13

4.7 二叉查找树使数据搜索更有效

  • 📌 二叉查找树[插图]是指在链表的基础上往数组中追加元素时,考虑到数据的大小关系,将其分成左右两个方向的表现形式。例如,假设我们事先把50这个值保存到了数组中。那么,如果接下来的值比先前保存的数值大的话,就要将其放到右边,反之如果小的话就放在左边。但实际的内存并不会分成两个方向,这是在程序逻辑上实现的(图4-15)。[插图]图4-15 二叉查找树的模型(将树颠倒后的形状) ^907761-41-461-1000

    • ⏱ 2023-01-23 21:46:50
  • 📌 只要在程序开发中多花一些心思,我们就可以熟练地使用内存、实现栈处理、链表处理、二叉查找树处理等,这一点想必大家都清楚了。不过,大家还必须理解为什么要进行这些处理。 ^907761-41-1649-1730

    • ⏱ 2023-01-23 21:49:32

第5章 内存和磁盘的亲密关系

  • 📌 磁盘缓存是指,把从磁盘中读出的数据存储在内存中,当该数据再次被读取时,不是从磁盘而是直接从内存中高速读出。 ^907761-42-1543-1596

    • ⏱ 2023-01-24 13:35:09
  • 📌 利用电流来实现存储的内存,同利用磁效应来实现存储的磁盘,还是有差异的。而从存储容量来看,内存是高速高价,而磁盘则是低速廉价。 ^907761-42-2089-2151

    • ⏱ 2023-01-24 13:36:32

5.1 不读入内存就无法运行

  • 📌 磁盘中存储的程序,必须要加载到内存后才能运行。在磁盘中保存的原始程序是无法直接运行的。这是因为,负责解析和运行程序内容的CPU,需要通过内部程序计数器来指定内存地址,然后才能读出程序。 ^907761-43-689-855
    • ⏱ 2023-01-24 23:35:07

5.2 磁盘缓存加快了磁盘访问速度

  • 📌 磁盘缓存指的是把从磁盘中读出的数据存储到内存空间中的方式。 ^907761-44-598-634

    • ⏱ 2023-01-24 23:35:56
  • 📌 把低速设备的数据保存在高速设备中,需要时可以直接将其从高速设备中读出,这种缓存的方式在其他情况下也会用到。 ^907761-44-1154-1233

    • ⏱ 2023-01-24 23:51:31

5.3 虚拟内存把磁盘作为部分内存来使用

  • 📌 虚拟内存是指把磁盘的一部分作为假想的内存来使用。这与磁盘缓存是假想的磁盘(实际上是内存)相对,虚拟内存是假想的内存(实际上是磁盘)。 ^907761-45-518-591

    • ⏱ 2023-01-24 23:52:51
  • 📌 虚拟内存的方法有分页式和分段式两种。Windows采用的是分页式。该方式是指,在不考虑程序构造的情况下,把运行的程序按照一定大小的页(page)进行分割,并以页为单位在内存和磁盘间进行置换。在分页式中,我们把磁盘的内容读出到内存称为Page In,把内存的内容写入磁盘称为Page Out。一般情况下,Windows计算机的页的大小是4KB。也就是说,把大程序用4KB的页来进行切分,并以页为单位放入磁盘(虚拟内存)或内存中(图5-3)。 ^907761-45-970-1372

    • ⏱ 2023-01-24 23:55:07

5.4 节约内存的编程方法

  • 📌 (1)通过DLL文件实现函数共有 ^907761-46-1236-1252

    • ⏱ 2023-01-24 23:57:36
  • 📌 (2)通过调用_stdcall来减小程序文件的大小 ^907761-46-2862-2887

    • ⏱ 2023-01-24 23:59:08

6.4 通过莫尔斯编码来看哈夫曼算法的基础

  • 📌 夫曼算法的关键就在于“多次出现的数据用小于8位的字节数来表示,不常用的数据则可以用超过8位的字节数来表示” ^907761-52-835-888
    • ⏱ 2023-01-25 00:22:58

7.7 BIOS和引导

  • 📌 引导程序是存储在启动驱动器起始区域的小程序。 ^907761-64-620-649

    • ⏱ 2023-01-25 23:20:59
  • 📌 引导程序的功能是把在硬盘等记录的OS加载到内存中运行。虽然启动应用是OS的功能,但OS并不能自己启动自己,而是通过引导程序来启动。 ^907761-64-747-812

    • ⏱ 2023-01-25 23:22:02

8.2 本地代码的内容

  • 📌 Dump是指把文件的内容,每个字节用2位十六进制数来表示的方式。 ^907761-67-1032-1071
    • ⏱ 2023-01-26 00:11:21

8.5 启动及库文件

  • 📌 sprintf()等函数,不是通过源代码形式而是通过库文件形式和编译器一起提供的。这样的函数称为标准函数。之所以使用库文件,是为了简化为链接器的参数指定多个目标文件这一过程。 ^907761-70-2123-2236
    • ⏱ 2023-01-26 00:20:17

8.7 可执行文件运行时的必要条件

  • 📌 那就是EXE文件中给变量及函数分配了虚拟的内存地址。在程序运行时,虚拟的内存地址会转换成实际的内存地址。链接器会在EXE文件的开头,追加转换内存地址所需的必要信息。这个信息称为再配置信息。 ^907761-72-834-954

    • ⏱ 2023-01-26 00:23:22
  • 📌 EXE文件的再配置信息,就成为了变量和函数的相对地址 ^907761-72-983-1009

    • ⏱ 2023-01-26 00:23:42
  • 📌 相对地址表示的是相对于基点地址的偏移量,也就是相对距离。 ^907761-72-1010-1038

    • ⏱ 2023-01-26 00:23:47

8.8 程序加载时会生成栈和堆

  • 📌 程序加载时会生成栈和堆 ^907761-73-397-408

    • ⏱ 2023-01-26 00:25:13
  • 📌 在内存的使用方法上,二者存在些许不同。栈中对数据进行存储和舍弃(清理处理)的代码,是由编译器自动生成的,因此不需要程序员的参与。使用栈的数据的内存空间,每当函数被调用时都会得到申请分配,并在函数处理完毕后自动释放。与此相对,堆的内存空间,则要根据程序员编写的程序,来明确进行申请分配或释放。 ^907761-73-1559-1704

    • ⏱ 2023-01-26 23:45:08

8.9 有点难度的Q&A

  • 📌 编译器是在运行前对所有源代码进行解释处理的。而解释器则是在运行时对源代码的内容一行一行地进行解释处理的。 ^907761-74-516-568
    • ⏱ 2023-01-26 23:46:22

第9章 操作系统和应用的关系

  • 📌 .监控程序也可以说是操作系统的原型。 ^907761-75-1465-1483
    • ⏱ 2023-01-26 23:49:21

9.1 操作系统功能的历史

  • 📌 有人开发出了仅具有加载和运行功能的监控程序,这就是操作系统的原型。 ^907761-76-755-814

    • ⏱ 2023-01-26 23:50:54
  • 📌 操作系统本身并不是单独的程序,而是多个程序的集合体 ^907761-76-1808-1833

    • ⏱ 2023-01-26 23:51:51

9.2 要意识到操作系统的存在

  • 📌 要想成为一个全面的程序员,有一点需要清楚的是,掌握基本的硬件知识,并借助操作系统进行抽象化,可以大大提高编程效率。 ^907761-77-692-749

    • ⏱ 2023-01-26 23:53:13
  • 📌 在操作系统这个运行环境下,应用并不是直接控制硬件,而是通过操作系统来间接控制硬件的。变量定义中涉及的内存的申请分配,以及time()和printf()这些函数的运行结果,都不是面向硬件而是面向操作系统的。操作系统收到应用发出的指令后,首先会对该指令进行解释,然后会对时钟IC(实时时钟)和显示器用的I/O进行控制。 ^907761-77-2076-2355

    • ⏱ 2023-01-26 23:54:51

9.3 系统调用和高级编程语言的移植性

  • 📌 高级编程语言的机制就是,使用独自的函数名,然后再在编译时将其转换成相应操作系统的系统调用(也有可能是多个系统调用的组合) ^907761-78-854-914
    • ⏱ 2023-01-26 23:56:22

10.1 汇编语言和本地代码是一一对应的

  • 📌 这些缩写称为助记符,使用助记符的编程语言称为汇编语言。 ^907761-83-761-840

    • ⏱ 2023-01-27 16:00:36
  • 📌 不过,即使是用汇编语言编写的源代码,最终也必须要转换成本地代码才能运行。负责转换工作的程序称为汇编器,转换这一处理本身称为汇编。在将源代码转换成本地代码这个功能方面,汇编器和编译器是同样的。 ^907761-83-921-1068

    • ⏱ 2023-01-27 16:00:51

10.2 通过编译器输出汇编语言的源代码

  • 📌 汇编语言源文件的扩展名,通常用“.asm”来表示 ^907761-84-2084-2108
    • ⏱ 2023-01-27 16:03:21

10.3 不会转换成本地代码的伪指令

  • 📌 汇编语言的源代码,是由转换成本地代码的指令(后面讲述的操作码)和针对汇编器的伪指令构成的。 ^907761-85-569-640
    • ⏱ 2023-01-27 16:05:00

10.4 汇编语言的语法是“操作码+操作数”

  • 📌 表10-2 x86系列CPU的主要寄存器 ^907761-86-2037-2369
    • ⏱ 2023-01-27 16:14:07

10.5 最常用的mov指令

  • 📌 dword ptr(double word pointer)表示的是从指定内存地址读出4字节的数据 ^907761-87-954-1003
    • ⏱ 2023-01-27 16:09:59

10.7 函数调用机制

  • 📌 函数调用是栈发挥大作用的场合。 ^907761-89-533-548

    • ⏱ 2023-01-27 16:12:17
  • 📌 在汇编语言中,函数名表示的是函数所在的内存地址 ^907761-89-1369-1392

    • ⏱ 2023-01-27 16:17:14

10.8 函数内部的处理

  • 📌 (2)中把负责管理栈地址的esp寄存器的值赋值到了ebp寄存器中。这是因为,在mov指令中方括号内的参数,是不允许指定esp寄存器的。因此,这里就采用了不直接通过esp,而是用ebp寄存器来读写栈内容的方法。 ^907761-90-1055-1159

    • ⏱ 2023-01-27 16:25:28
  • 📌 函数的参数是通过栈来传递,返回值是通过寄存器来返回的 ^907761-90-1503-1536

    • ⏱ 2023-01-27 16:22:21

10.13 了解程序运行方式的必要性

  • 📌 在多线程处理中,用汇编语言记述的代码每运行1行,处理都有可能切换到其他线程(函数)中。 ^907761-95-2088-2131

    • ⏱ 2023-01-27 16:30:20
  • 📌 为了避免该bug,我们可以采用以函数或C语言源代码的行为单位来禁止线程切换的锁定方法。通过锁定,在特定范围内的处理完成之前,处理不会被切换到其他函数中。 ^907761-95-2685-2787

    • ⏱ 2023-01-27 16:30:36
  • 📌 没有汇编语言经验的程序员,就相当于只知道汽车的驾驶方法而不了解汽车结构的驾驶员。对这样的驾驶员来说,如果汽车出现了故障或奇怪的现象,他们就无法自己找到原因。不了解汽车结构的话,开车的时候还可能会浪费油。这样的话,作为职业驾驶员是不合格的。与此相对,有汇编语言经验的程序员,也就相当于了解计算机和程序机制的驾驶员,他们不仅能自己解决问题,还能在驾驶过程中省油。 ^907761-95-3047-3226

    • ⏱ 2023-01-27 16:31:14

11.2 支撑硬件输入输出的IN指令和OUT指令

  • 📌 I/O 控制器。由于电压不同,数字信号及模拟信号的电流特性也不同,计算机主机和外围设备是无法直接连接的。为了解决这个问题,I/O控制器就很有必要了。 ^907761-98-1159-1240

    • ⏱ 2023-01-27 16:35:04
  • 📌 I/O控制器中有用于临时保存输入输出数据的内存。这个内存就是端口。 ^907761-98-1314-1373

    • ⏱ 2023-01-27 16:35:24

11.3 编写测试用的输入输出程序

  • 📌 在大部分C语言的处理(编译器的种类)中,只要使用_asm{和}括起来,就可以在其中记述助记符。也就是说,这样就可以编写C语言和汇编语言混合的源代码 ^907761-99-631-704
    • ⏱ 2023-01-27 16:38:30

11.4 外围设备的中断请求

  • 📌 中断处理在硬件控制中担当着重要角色。因为如果没有中断处理,就有可能出现处理无法顺畅进行的情况 ^907761-100-664-710

    • ⏱ 2023-01-27 16:42:16
  • 📌 实施中断请求的是连接外围设备的I/O控制器,负责实施中断处理程序的是CPU。 ^907761-100-1258-1296

    • ⏱ 2023-01-27 16:42:42

12.4 程序生成随机数的方法

  • 📌 在C语言中,虽然该公式的实体是隐藏的,但只要调用rand()函数,就可以得到结果(随机数)。不过,由于借助公式产生的随机数具有一定的规律性,因此并不是真正的随机数,通常称为伪随机数。不过,虽然是伪随机数,仍然十分有用。 ^907761-109-1011-1146
    • ⏱ 2023-01-27 16:46:03

读书笔记

1.2 CPU是寄存器的集合体

划线评论

  • 📌 程序是把寄存器作为对象来描述的。 ^37417557-7FnM5yINq
    • 💭 编程: 面向寄存器编程 or 编写寄存器能理解的文本
    • ⏱ 2023-01-19 16:36:40

1.6 通过地址和索引实现数组

划线评论

  • 📌 CPU则会把基址寄存器+变址寄存器的值解释为实际查看的内存地址。变址寄存器的值就相当于高级编程语言程序中数组的索引功能。 ^37417557-7Frkzw2Ue
    • 💭 转
      基址寄存器存储数组中打头的那个元素在内存中的实际地址,而变址寄存器存储的是元素索引。两者结合,就能准确找到所有的元素。
    • ⏱ 2023-01-22 00:43:12

4.3 简单的指针

划线评论

  • 📌 代码清单4-2 各种数据类型指针的定义[插图]假设d、e、f的值都是100。在这种情况下,使用d时就能够从编号100的地址中读写1个字节的数据,使用e时就是2个字节(100地址和101地址)的数据,使用f时就是4个字节(100地址~103地址)的数据。怎么样?指针是不是很简单呢(图4-5)。 ^37417557-7FuaL82l3
    • 💭 指针也有类型的意义
    • ⏱ 2023-01-23 21:33:22

7.7 BIOS和引导

划线评论

  • 📌 Bootstrap的原意是指靴子上部的“拔靴带”。BIOS这样小的程序(拔靴带),可以带动(启动)操作系统这样的大程序(靴子),所以由此得名 ^37417557-7FxkD681F
    • 💭 原来是这么来的
    • ⏱ 2023-01-25 23:24:06

8.3 编译器负责转换源代码

划线评论

  • 📌 还有一种交叉编译器,它生成的是和运行环境中的CPU不同的CPU所使用的本地代码。 ^37417557-7FxnSVeIF
    • 💭 例如golang
    • ⏱ 2023-01-26 00:13:48

本书评论

书评 No.1

经典书籍 ^37417557-7FzXvNhwS
⏱ 2023-01-27 16:51:08