(七)if/else就是goto

一、CPU如何执行指令

CPU上有数以亿计的晶体管组层的复杂电路,我们先不用管具体电路如何实现;逻辑上我们可以认为CPU由许多寄存器组成,而这些寄存器又由许多锁存器和触发器组成,N个锁存器或触发器就可以构成一个N位寄存器,例如64位CPU是指其寄存器是64位的。

CPU中有以下三种典型的寄存器,这里重点讲一下:

  1. PC寄存器:用来存放下一条要执行指令的存储地址;
  2. 指令寄存器:存放当前正在执行的指令;
  3. 条件寄存器:内部用一个标记位保存CPU算数运算或逻辑运算的结果;

        程序执行时CPU不断依据PC寄存器的地址取出一条条指令交给指令寄存器执行,然后PC寄存器中指令地址不断根据指令长度递增,由此可知指令一般是顺序存放的,例外情况是遇到跳转指令会直接替换PC寄存器中的指令地址到指定地址。

二、以if/else看指令执行和跳转

示例代码:

// test.c
#include <time.h>
#include <stdlib.h>
int main()
{
  srand(time(NULL));
  int r = rand() % 2;
  int a = 10;
  if (r == 0)
  {
    a = 1;
  } else {
    a = 2;
  } 

编译结果:

    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. if判断被编译为 cmpjne两条指令,rbp-0x4地址寄存器中的数和0进行比较将比较结果存入条件码寄存器,如果r为0,则将0标志条件码记为1;
  2. 接着顺序执行jne指令,jne 表示 jump not equal ,此时查看条件码寄存器,如果条件码寄存器值为0则直接将PC寄存器中下一条指令地址置为4a,进而跳转执行4a行指令;
  3. 末尾51行mov 命令 eax表示一个累加器,0x0实际是一个占位符,整个这条指令相当于为main方法生成了一个默认为0的返回值在累加器里面。
  4. 假若r为0,则程序会顺序执行完41后在48跳转到51

三、循环应该怎么干

示例代码:

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

编译结果:

    for (int i = 0; i < 3; i++)
   b:   c7 45 f8 00 00 00 00    mov    DWORD PTR [rbp-0x8],0x0
  12:   eb 0a                   jmp    1e <main+0x1e>
    {
        a += i;
  14:   8b 45 f8                mov    eax,DWORD PTR [rbp-0x8]
  17:   01 45 fc                add    DWORD PTR [rbp-0x4],eax
    for (int i = 0; i < 3; i++)
  1a:   83 45 f8 01             add    DWORD PTR [rbp-0x8],0x1
  1e:   83 7d f8 02             cmp    DWORD PTR [rbp-0x8],0x2
  22:   7e f0                   jle    14 <main+0x14>
  24:   b8 00 00 00 00          mov    eax,0x0
    }

分析:

  1. b行为i赋初始值0,然后顺序执行跳转到1e行;
  2. 1e行 cmp 指令比较i的值与2
  3. 22行判断比较结果小鱼等于2则跳转回14行
  4. 直到jle条件不满足,顺序执行24在累加器中存入默认返回值0.

可见循环操作就是可以将指令执行未知“拨回”已经执行过的行;通过PC寄存器保存下一条要执行的指令、条件码寄存器保存条件运算结果、指令寄存器保存当前执行的指令再加上可以直接修改PC寄存器中下条指令的地址,就可以实现条件分支运算和循环。

posted @ 2020-04-26 16:42  rxmind  阅读(312)  评论(0)    收藏  举报