
CPU 和内存,本质上都属于集成电路(Integrated Circuit,IC)。
CPU 内部大致由下面几部分组成:
内存,这里通常说的是主存储器。它由可读写的存储元件构成,每个字节都分配了一个编号,这个编号就叫地址。
很多人会把“128G”“256G”这种东西叫内存,但严格来说,那一般说的是存储空间,不叫主存。它通常对应的是硬盘、SSD 这类存储设备。
为什么要把寄存器单独讲?
因为它是程序运行时非常核心的描述对象。
先看看它为什么会出现。
在没有寄存器的时候,数据和程序都放在内存里,执行过程大致就是:
CPU <- 内存(取指令/数据)
CPU -> 内存(写回结果)
但问题来了。
cpu运算速度极快,大约0.3纳秒,而内存的速度,大约100纳秒,内存太慢了,严重拖累cpu的速度
因此,寄存器出现了,它的速度大约为1纳秒
那问题又来了,为什么不直接用寄存器去替代内存,这不快多了吗?
看到这里,你能发现一个规律:
从 CPU -> 寄存器 -> 内存 -> 硬盘 速度是越来越慢的,但容量刚好反过来,是越来越大的。
这其实就是计算机里一个很经典的取舍:
越快的东西,通常越贵、越小。越大的东西,通常越慢。
机器语言指令的本质是电子信号。
但电子信号人看不懂,所以人们就用一些英语单词或者缩写,去表示这些指令的功能,这就成了汇编语言。
所以你可以先这样记:
把汇编语言变成机器语言的过程,叫**汇编(assemble)。 反过来把机器语言还原成汇编形式,就叫反汇编(disassemble)**。
在机器语言这个层面上,程序的大部分操作,本质上都是围绕寄存器完成的。
寄存器也分很多种类型:

当然,只有一行程序是干不了什么事的。
那程序是怎么按照指定顺序一条条运行的?
这里有个非常关键的角色: 程序计数器
你可以把它理解成:
它专门记着“下一条要执行哪一行”。
CPU 每执行完一条指令,程序计数器通常就自动指向下一条。 如果遇到跳转、函数调用这些情况,程序计数器就会被改成别的地址。
流程意思:把 123 和 456 两个数值相加,并输出到屏幕中

程序流程大致分三种:
上面这种一条一条往下走的,就是顺序执行。
条件分支的意思就是:
如果满足某个条件,那就别往下老老实实走了,直接跳去别的地方。

可以看出,当 0102 的条件被满足时,程序会跳转到 0104。
那 CPU 怎么知道“条件满足了没有”呢?
这里就要用到标志寄存器。
标志寄存器不会去保存“累加器和通用寄存器的值”,它保存的是上一次运算之后的结果状态。
比如:
CPU 在每次运算后,都会自动根据结果去改这些标志位。
然后到了条件跳转这里,CPU 就看标志寄存器里的状态,决定跳还是不跳。
循环本质上其实没有那么神秘。
它就是:
条件分支 + 跳回去再来一次
比如你想把 1 加到 100:
这里能看出,循环就是 "判断" + "跳转"
先来看什么是函数。
早期程序如果什么都从头写到尾,就会有一个很明显的问题:
有些逻辑完全一样,难道每次都重新写一遍?
于是人们就想到:
能不能把一段重复的代码单独放在一个地方,需要的时候跳过去执行,执行完再回来?
于是函数就出现了。
同时也有了两种很关键的指令:

你可以把它理解成:
这里会用到两个寄存器:
说得再白一点:
比如:
数组起始地址是
每个元素占 4 个字节
我要取下标为 3 的元素1000
那实际地址就是:
1000 + 3 × 4 = 1012
也就是说,数组下标并不是直接“写在内存里”的,而是通过:
起始地址 + 偏移量
算出来的。
计算机内存地址范围 ,32 位寄存器就可以访问全部地址。00000000 ~ FFFFFFFF
而访问连续内存,比如数组,用基址寄存器和变址寄存器会更高效。因为你不用每次都重新找一整块地址,只要知道“从哪里开始,偏多少”就够了。
程序之所以能跑起来,就是CPU对下面这个过程不断重复:
所以你看到的程序,表面上是一大堆代码。
但到了 CPU 这一层,它其实就是:
取指令、放寄存器、做运算、判断要不要跳、然后继续往下跑。