阅读 49

3.循环与选择 if and switch

循环&选择

cmp(Compare)比较指令

   CMP 把一个寄存器的内容和另一个寄存器的内容或立即数进行比较。但不存储结果,只是正确的更改标志。    一般CMP做完判断后会进行跳转,后面通常会跟上B指令!

  • BL 标号:跳转到标号处执行
  • B.LT 标号:比价结果是小于(less than),执行标号,否则不跳转
  • B.LE 标号:比较结果是小于等于(less than or qeual to),执行标号,否则不跳转
  • B.GT 标号:比较结果是大于(greater than),执行标号,否则不跳转
  • B.GE 标号:比较结果是大于等于(greater than or equal to),执行标号,否则不跳转
  • B.EQ 标号:比较结果是等于(equal to),执行标号,否则不跳转
  • B.NE 标号:比较结果是不等于(not equal to),执行标号,否则不跳转
  • B.LS 标号:比较结果是无符号小于等于,执行标号,否则不跳转
  • B.LO 标号:比较结果是无符号小于,执行标号,否则不跳转
  • B.HI 标号:比较结果是无符号大于,执行标号,否则不跳转
  • B.HS 标号:比较结果是无符号大于等于,执行标号,否则不跳转
void func(int a,int b){
    if (a > b) {
        g = a;
    }else{
        g = b;
    }
}
复制代码
  • if的比较汇编

E0ECF81DEEB1DAC3ECF58DB9C1BCF2BD.jpg

  • CMP指令比较
  • CMP其实是做减法,然后不影响目标寄存器,只影响标记寄存器
  • for

BF21E1B01F4F34C7509CD60E28534125.jpg

5F39619519011AC41A697792BD87F676.jpg

  • do while 循环: 判断条件在后面,满足条件往外跳
  • for 循环 和 while 循环很像,判断条件在里面,不满足就往外跳。

##Switch 1、假设switch语句的分支比较少的时候(例如3,少于4的时候没有意义)没有必要使用此结构,相当于if。 2、各个分支常量的差值较大的时候,编译器会在效率还是内存进行取舍,这个时候编译器还是会编译成类似于if,else的结构。 3、在分支比较多的时候:在编译的时候会生成一个表(跳转表每个地址四个字节)。

  • switch
void funcA(int a){
    switch (a) {//
        case 1:
            printf("打坐");
            break;
        case 2:
            printf("加红");
            break;
        case 3:
            printf("加蓝");
            break;
        case 4:
            printf("打怪");
            break;
            
        default:
            printf("啥都不干");
            break;
    }
}
复制代码
  • 汇编解析
004--选择`funcA:
    0x102b6e0f0 <+0>:   sub    sp, sp, #0x20             ; =0x20  //开辟栈空间
    0x102b6e0f4 <+4>:   stp    x29, x30, [sp, #0x10]              //X29 X30寄存器入栈
    0x102b6e0f8 <+8>:   add    x29, sp, #0x10            ; =0x10  //x29 指向栈底
    0x102b6e0fc <+12>:  stur   w0, [x29, #-0x4]                   //w0 参数入栈 
    0x102b6e100 <+16>:  ldur   w8, [x29, #-0x4]                   //w8 取出值 即 w0 中的值 
    0x102b6e104 <+20>:  subs   w8, w8, #0x1              ; =0x1  // w8 - 1 '1'是最小的case
    0x102b6e108 <+24>:  mov    x9, x8                            //x8 的值-> x9  
    0x102b6e10c <+28>:  ubfx   x9, x9, #0, #32                   //将x9的高32位清0 将#0--#32位 清零 保留 后面位的值
    0x102b6e110 <+32>:  cmp    x9, #0x3                  ; =0x3  //x9与3作比较  3 是最小case 和 最大 case 的差
    0x102b6e114 <+36>:  str    x9, [sp]                          //x9入栈保存
    0x102b6e118 <+40>:  b.hi   0x102b6e174               ; <+132> at main.m  //hi无符号 大于 跳转到 0x102b6e174 否则继续往下走 说明case在区间之内
    0x102b6e11c <+44>:  adrp   x8, 0 
    0x102b6e120 <+48>:  add    x8, x8, #0x18c            ; =0x18c //x8 = 0x102b6e18c x8->一个存放了 最大case-最小case+defualt个数的负数的表 用于地址偏移
    0x102b6e124 <+52>:  ldr    x11, [sp]                  //x9->x11
    0x102b6e128 <+56>:  ldrsw  x10, [x8, x11, lsl #2]     //x11左移2位 1->4 再与 x8 相加 赋值给 x10
    0x102b6e12c <+60>:  add    x9, x8, x10
    0x102b6e130 <+64>:  br     x9 
    0x102b6e134 <+68>:  adrp   x0, 1
    0x102b6e138 <+72>:  add    x0, x0, #0xf69            ; =0xf69 
    0x102b6e13c <+76>:  bl     0x102b6e588               ; symbol stub for: printf
    0x102b6e140 <+80>:  b      0x102b6e180               ; <+144> at main.m:30:1
    0x102b6e144 <+84>:  adrp   x0, 1                     
   // - 将PC寄存器的低12位清零
   // - 将1的值,左移12位! 16进制就是0x1000
   // - 以上两个结果相加放入x0寄存器
   // 0x102b6e144->0x102b6e000-> '+1' -> 0x102b6f000 -> 放入到寄存器x0
    0x102b6e148 <+88>:  add    x0, x0, #0xf70            ; =0xf70        //x0 + 0xf70 -> 0x102b6ff70 -> 放入到寄存器x0
    0x102b6e14c <+92>:  bl     0x102b6e588               ; symbol stub for: printf
    0x102b6e150 <+96>:  b      0x102b6e180               ; <+144> at main.m:30:1
    0x102b6e154 <+100>: adrp   x0, 1
    0x102b6e158 <+104>: add    x0, x0, #0xf77            ; =0xf77 
    0x102b6e15c <+108>: bl     0x102b6e588               ; symbol stub for: printf
    0x102b6e160 <+112>: b      0x102b6e180               ; <+144> at main.m:30:1
    0x102b6e164 <+116>: adrp   x0, 1
    0x102b6e168 <+120>: add    x0, x0, #0xf7e            ; =0xf7e 
    0x102b6e16c <+124>: bl     0x102b6e588               ; symbol stub for: printf
    0x102b6e170 <+128>: b      0x102b6e180               ; <+144> at main.m:30:1
    0x102b6e174 <+132>: adrp   x0, 1
    0x102b6e178 <+136>: add    x0, x0, #0xf85            ; =0xf85 
    0x102b6e17c <+140>: bl     0x102b6e588               ; symbol stub for: printf
    0x102b6e180 <+144>: ldp    x29, x30, [sp, #0x10]
    0x102b6e184 <+148>: add    sp, sp, #0x20             ; =0x20 
    0x102b6e188 <+152>: ret    
复制代码

选择&指针

  • 编译器优化
    • 编译器的优化,LLVM优化过程,优化的是我们的指令多少
    • 无用代码(去掉之后对执行结果没有影响)会被优化掉
  • Swift
    • 分支少于3个(switch没有啥意义),底层代码和if-else一致
    • 分支段多,根据情况,编译器会生成一个表进行跳转,利用空间换取事件,效率非常高
    • 各个分支常量差值较大的时候,编译器会在效率和内存中进行取舍
  • 指针
    • 指针的宽度:指针的宽度是指,它所指向的数据类型的宽度!
    • 指针的自增自减是按指向的数据类型(指针的宽度)来运算的。
文章分类
iOS
文章标签