计算机原理学习与分享:if else for while是个啥?

吐槽君 分类:javascript

CPU是如何执行指令的?

我们先来简单了解一下CPU。

逻辑上我们简单的理解CPU是由一堆寄存器组成的,代码计算的时候就是执行不同的寄存器。

寄存器里面有触发器和锁存器,简单理解是不同的电路,用来保存数据,但是原理不同。

一般我们说的64位处理器,就是说的寄存器有64位。

都有些啥寄存器?

一个CPU里面有很多不同的寄存器。比较重要的以下三种:

  1. PC寄存器,也叫指令地址寄存器。用来存放下一条需要执行的计算机指令,主要负责程序的运行顺序。
  2. 指令寄存器,存放当前执行的指令
  3. 条件码寄存器,用来存放比较大小,或者逻辑运算得出来的结果,有CF,ZF,SF,OF等条件码,
  4. 其他寄存器,什么加法寄存器,通用寄存器之类的

一个程序执行的时候,CPU根据PC寄存器里的地址,从内存里把要执行的指令读到指令寄存器里执行,然后指令长短自增,读取一下一条指令。

所以一个程序再内存里是顺序保存的,也会一条条加载。

而J指令,跳转指令会修改PC寄存器里的地址值。这样就不是按内存顺序加载了。也就是我们代码里面的if else while for 等了

if else 是咋实现的?

if (r == 0) {
 a = 1;
} else {
 a = 2; 
}
 

上面是if else 语句,翻译成汇编,是这样的:

if (r == 0)
  3b:   83 7d fc 00             cmp    DWORD PTR [rbp-0x4],0x0
  3f:   75 09                   jne    4a <main+0x4a>
    {
        a = 1;
  41:   c7 45 f8 01 00 00 00    mov    DWORD PTR [rbp-0x8],0x1
  48:   eb 07                   jmp    51 <main+0x51>
    }
    else
    {
        a = 2;
  4a:   c7 45 f8 02 00 00 00    mov    DWORD PTR [rbp-0x8],0x2
  51:   b8 00 00 00 00          mov    eax,0x0
    }
 
  1. cmp 指令比较两个操作数的值,DWORD PTR代表数据类型是32位整数,第一个操作数[rbp-0x4]是寄存器里存的内存的地址,这里指的是r的值,第二个操作数0x0就是0。
  2. cmp比较过后存到条件码寄存器中。
  3. 如果r == 0为true,就把**零标志条件码(zero flag)**设置为1
  4. cmp执行完,PC寄存器自增,开始执行jne
  5. jne先会查看零标志位,如果为0,则跳转到4a这个位置,CPU就把4a地址里的指令加载到指令寄存器来执行。
  6. 到了4a地址,开始执行mov,[rbp-0x8]是32位整型的寄存器地址,0x2是2的16进制,mov把2设置到[rbp-0x8]寄存器里。是一个赋值操作,这里PC寄存器继续自增执行下一条mov
  7. 这里的mov 后面的eax代表累加寄存器,0x0是0的16进制,这是一条占位符。主要是用来指示上面如果if符合条件的a=1执行完,就直接跳转到这里。
  8. 如果没有返回值,编译器会自动添加上return 0,汇编就是mov 0x0,起到占位符的作用

可以看到 if else 就是内存之间的跳转,根据cmp存在条件寄存器不同的值,再通过跳转jne(≠)相不相等jle(≤)小于等于,来跳转到不同的位置去执行代码。

for循环咋实现的?

int main()
{
    int a = 0;
    for (int i = 0; i < 3; i++)
    {
        a += i;
    }
}
 

对应的汇编

for (int i = 0; i <= 2; i++)
   b:   c7 45 f8 00 00 00 00    mov    DWORD PTR [rbp-0x4],0x0
  12:   eb 0a                   jmp    1e 
    {
        a += i;
  14:   8b 45 f8                mov    eax,DWORD PTR [rbp-0x4]
  17:   01 45 fc                add    DWORD PTR [rbp-0x8],eax

  1a:   83 45 f8 01             add    DWORD PTR [rbp-0x4],0x1
  1e:   83 7d f8 02             cmp    DWORD PTR [rbp-0x4],0x2
  22:   7e f0                   jle    14 
  24:   b8 00 00 00 00          mov    eax,0x0
    }
 
  1. mov int类型寄存器设值为0,
  2. jmp 跳转到 1e地址
  3. mov 从int类型寄存器添加到累加寄存器
  4. add 将累加寄存器的值添加到整型寄存器里面
  5. add 寄存器中添加 1(0x1)
  6. cmp 比较寄存器中1(0x1),2(0x2),然后存到条件寄存器里面
  7. jle 根据条件寄存器判断1≤2,跳转到编译之前的14地址,不满足则PC寄存器自增向下执行
  8. mov 返回一个空

可以看到for循环也是cmp对比了前后的数据,也是一个比较之后的jle(≤)的跳转。

总结

内存上的代码都是按顺序排列好的,执行的时候也是按顺序执行,if else 实际上是PC寄存器的指针跳转,for while 实际上是标记了开始的位置,并写个判断条件,满足条件跳转到开始的位置再顺序执行就实现了我们经常使用的 if else for。

回复

我来回复
  • 暂无回复内容