导图社区 《程序是怎样跑起来的》
本书为计算机从业者介绍了计算机的组成、CPU、二进制的运算、内存、操作系统、程序运行、汇编、硬件控制、机器学习等内容,让读者深入了解程序是怎样从源文件经历各个过程在你的计算机中运行起来的,是计算机爱好者和从业人员必读的科普书籍。
编辑于2024-01-18 19:32:06程序是怎样跑起来的
1.程序的处理器:CPU
由寄存器,控制器,运算器,时钟四部分组成。使用电流信号来连通。
寄存器:暂存数据和指令
控制器:控制寄存器中的数据和指令的读入
时钟:程序计时
运算器:运算从寄存器中读入的数据
CPU是各种功能寄存器的集合
寄存器只能处理机器语言
机器语言是通过高级编程语言编译后得到的
寄存器1:程序计数器
通过执行地址指令决定程序的执行
寄存器2:标志寄存器
保存运算结果(正,负,零,溢出,奇偶校验)
函数调用
是通过把程序计数器的值设定成函数的存储地址来实现的
使用栈来获取call地址和return的地址
数组的存储
使用基址寄存器存储数组内容,使用变址寄存器来存储数组索引
2.数据用二进制表示
为何用二进制表示:计算机内部是用二极管表示的通或者不通两种情况
二进制最小的单位是比特,也就是位,代表的是二进制的一个数字的位。
二进制的基本单位是字节,一个字节是8位
二进制的计算
二进制与十进制的转换方法:用二进制的位次的幂的结果相加得到十进制的数
十进制数的运算在计算机中依然是转化成二进制的数字来计算:例如二进制的左移一位相当于数字乘2
计算机内部的减法是使用加法来实现的,这里使用“补码”
二进制的最高位是符号位,1表示负数,0表示正数
表示负数时需要用“补码”来计算
求一个负数,先将用8位二进制数来表示正数,然后所有位数上的数字取反,再把结果加1
在计算加法时,最高位如果超出了计算的范围,就会溢出,溢出的值计算机会自动抛弃
无符号类型就是全是正数的二进制。有符号类型就是把最高位拿走用于表示符号,只剩下n-1位的位次,因此正负值各占一半。
逻辑右移和算数右移的区别
逻辑右移:就相当于图像右移,直接在左边空出来的位置填充0
算数右移:二进制的位数整体向右移动,空出来的位置用0或者1填充
如果数值是用补数表示的负数值,那么右移后在空出来的最高位补 1,就可以正确地实现 1/2、1/4、1/8 等的数值运算。如果是正数,只需在最高位补 0 即可。
二进制数转化为十六进制数,长度可以变为原来1/4,更简洁明了
开头有0x的就是表示的十六进制数值
3.浮点数
用二进制来表示小数时,无法做到精确表示,只能做一个有精度范围的约数
浮点数的表现形式是IEEE标准
单精度浮点数(32位)
符号部分1,指数部分8,尾数部分23
双精度浮点数(64位)
符号部分1,指数部分11,尾数部分52
表达方法:正则表达式
EXCESS系统
EXCESS 系统表现是,通过将指数部分表示范围的中间值设为 0,使得负数不需要用符号来表示。
4.内存
内存可以读取数据,断电信息消失
数据信号引脚有8个,因此能表示8位,1个字节
地址信号引脚有10个,能表示1024个信号,就是1K
数据的类型不同,即使是同一个数值,占据的内存大小也不同(因此在程序中定义变量类型时为了不浪费每一层的8位,就需要调整好类型的位次,来尽可能紧凑的使用内存)
指针
指针也是一种变量,它所表示的不是数据的值,而是存储着数据的内存的地址,通过使用指针,可以对任意指定地址的数据进行读写
数组
在内存中用连续的地址来存储。用index来指示每个数据的地址。
栈和队列
栈和队列不使用索引来进行存取数据,但是可以以一定元素数的数组形式来划分一块内存区域,来实现内部的存取
栈:先进后出
队列:先进先出(使用环状缓冲区,可在一块固定大小的内存中反复存取)
链表
可以更加方便的增删改查
二叉树
方便进行检索
节约内存的方式
共用DLL文件来减少函数重复储存
通过调用 _stdcall 来减小程序文件的大小
5.磁盘
磁盘中存储的程序,必须要加载到内存后才能运行,负责解析和运行程序内容的 CPU,需要通过内部程序计数器来指定内存地址,然后才能读出程序
磁盘缓存加快了磁盘访问速度
虚拟内存:实际上还是磁盘的空间,不过把这部分空间划分成多页,在需要运行时不断的把页里面的内容读取到内存中
计算机一般将磁盘划分为扇区,以簇为单位进行存储,一个文件再小也要独占一个簇。
6.压缩数据
文件以字节为单位存储
RLE压缩算法
有限定条件,如果文件中重复内容比例不大,会造成文件反而扩大
哈夫曼算法
哈夫曼算法的关键就在于“多次出现的数据用小于 8 位的字节数来表示,不常用的数据则可以用超过 8 位的字节数来表示”
用哈夫曼树来安排每个字符的编码,频率高的在短位,频率低的在长位,且每个编码都作为二叉树的叶子结点
可逆压缩和非可逆压缩
7.程序的运行环境
运行环境:操作系统和计算机硬件
源代码->本机代码->运行
Windows 克服了 CPU 以外的硬件差异,使不同的机型可以兼容同一个程序
CPU不同,使用的机器语言也不同,因此同一个程序迁移到其他的CPU中时需要CPU专用的本地代码编译器重新编译成对应的本机代码
利用虚拟机获得其他操作系统环境
Virtual PC for MAC 可以使 Macintosh 这一硬件变得同 AT 兼容机一样,从而能在该硬件上安装 Windows
Java虚拟机
Java 虚拟机是一边把 Java 字节代码逐一转换成本机代码一边运行的
BIOS
BIOS 存储在 ROM 中,是预先内置在计算机主机内部的程序
BIOS 除了键盘、磁盘、显卡等基本控制程序外,还有启动“引导程序”的功能
8.从源文件到可执行文件
源代码需要编译成本机代码才能运行
本机代码的本质是十六位进制的数值序列
编译器负责把源代码翻译成本机代码
.c文件经过编译器编译后变为.obj文件,此时程序依然无法运行
连接器将多个目标文件拼接在一起生成一个EXE文件,这个过程叫链接,输入链接命令后才能生成.exe文件
库文件是由多个目标文件打包而成的。在链接时指定库文件,链接器就可以从中提取所需的目标文件,并将其与其他目标文件一起链接生成EXE文件。
Windows API是程序应用接口
API本质是函数,API的目标文件是动态链接库(DLL)的库文件(不实际存储目标文件,只提供目标文件的链接,用于程序运行时自动获取目标文件用)
包含目标文件本身,可以直接链接到EXE文件的库文件称为静态链接库(static link library)
运行可执行文件需要变量和函数
在EXE文件中,变量和函数被分配的内存地址都是虚拟的,在程序运行时,这些虚拟的内存地址会转换成实际的内存地址。链接器会在EXE文件的开头记录需要进行内存地址转换的各个位置,这些信息被称为重定位信息。
内存中的区域组成:变量空间,函数空间,堆空间,栈空间
栈用来存放函数中的局部变量和需要传的参数
栈空间是由编译器自动生成或者释放的,不需要手动操作
堆用来存放任意数据
堆空间是需要手动的分配和释放(malloc和free)(new和delete)
9.操作系统
本质
是一种具备加载和运行程序功能的监控程序
可移植性
高级编程语言在编辑源代码时使用的是通用语言,但是在不同的操作系统中编译成本机代码之后,程序调用的是本系统内的系统函数,这就是可移植性
硬件抽象化
操作系统和高级编程语言为硬件做了抽象化,使程序员不必再关注系统调用和硬件
Windows操作系统的特点
有32位和64位两个版本
通过API函数集提供系统调用
采用GUI
能以WYSIWYG的方式打印输出
提供多任务功能
提供网络和数据库功能
可通过即插即用自动安装设备驱动程序
10.汇编语言和本机代码
汇编语言
汇编语言使用助记符,是本机代码的指令
使用汇编语言编写的源代码也要转换成本机代码也才能运行
将汇编语言转换成本机代码的程序是汇编器,转换过程称为汇编
也可以把本机语言转换成汇编语言,转换过程称为反汇编
C语言编译器也可以将C语言源代码转换成汇编语言源代码
汇编语言中有两种指令
1.会被转换成本机代码的一般指令
2.专门针对汇编器的伪指令
伪指令负责告诉汇编器程序的结构和汇编的方法,因此也被称为汇编程序指令
汇编语言中以#号开头的是注释
语法
操作码
表示指令的动作
操作数
表示指令的操作对象
运行程序时会在寄存器开辟一块栈空间,调用的函数变量等使用这个栈,程序结束后清理栈空间
调用函数
从栈中取出参数并进行运算,将返回值存入eax寄存器,以及从栈中取出返回目标地址并让流程返回
变量
全局变量
在函数外部声明,程序中所有的函数都可以访问
局部变量
在函数内部声明,只能在声明他的函数中访问
循环
条件分支
11.访问硬件
程序通过操作系统访问硬件
输入输出指令
I/O控制器=端口
临时存放输入输出数据
用端口号开区分,也就是I/O地址
只要在in指令和out指令中指定端口号,就可以访问这个I/O控制器,完成输入输出操作。
中断处理
暂停当前的运行程序,转而运行其他程序
I/O控制器发出中断请求,CPU运行中断处理,两者之间用中断控制器来依次交给CPU处理
DMA
外部设备不经过CPU中转,直接和内存进行数据传输的方式,常用于网络、磁盘等设备
PIO
通过CPU在外部设备和内存之间传输数据的方式称为PIO
显示字符和图像
将数据存放在显存,就可以在显示器上展示出来
显卡上有独立的显存和图像处理器GPU
12.机器学习
概念
程序员只编写用于学习的程序,这个程序的内容是让计算机读取大量数据,然后学习这些数据的特征,并生成一个识别模型
有监督学习
有监督学习就是给计算机提供大量带正确答案的数据
步骤
(1)将学习数据和答案数据划分为训练数据和测试数据
(2)用学习算法学习训练数据并生成模型
(3)用测试数据评估模型的性能
机器学习的算法
支持向量机
工具
Python语言
Python中提供了包含各种机器学习相关功能的库
用Python解释器对事先编写好的源代码进行解释执行的脚本模式(script mode)
直接启动Python解释器,通过键盘逐行输入程序并解释执行的交互模式(interactive mode)(机器学习使用这个模式)
交叉验证
交叉验证是一种不断轮换训练数据和测试数据来进行机器学习的方法
可以检验学习模型的识别率是否存在因学习数据的类型而出现偏差的情况