我们在4、全局变量 & 循环选择和判断最后的时候提到了Switch
。
其中有一点,我们提到了表
。那么这张表
是怎么来的,里面又存放了什么数据,今天我们就详细的探讨一下。上一章我们说表
里面存放是case对应的要执行的代码的地址;其实更准确的讲,存放的是地址的偏移量,是以表头地址为参照的偏移量。大致如下:
![](https://img.haomeiwen.com/i1621748/f248fa260bc44e78.png)
表头地址 +
case
的偏移量,就可以找到对应的case
。也就是说Switch
并不是去一个一个的遍历每个case
。下面我们看一下真实的代码情况:![](https://img.haomeiwen.com/i1621748/33f78d0929f854e2.png)
看一下
func
的汇编代码:![](https://img.haomeiwen.com/i1621748/f81fc7af6b9c6e17.png)
![](https://img.haomeiwen.com/i1621748/17d6030847553b8d.png)
我们再接着往下分析,我们会看到这样一段代码:
ubfx x9, x9, #0, #32
这句代码的意思是:将x9的 高32位 清零,然后再将值赋值给x9;或者说将x9的 低32位 取出来,其他的用0补齐,得到的值赋值给x9
那么接下来的代码就是:
//w8里面的值与0x2相减,得到结果是 w8==5
0x1042ae010 <+20>: subs w8, w8, #0x2 ; =0x2
//将x8里面的值赋值给x9 ("注意:这里为什么要用`x8`而不是`w8`;因为上面的相减的结果可能是一个负数,可能会超过32位")
0x1042ae014 <+24>: mov x9, x8
//这一句上面已经解释过了
0x1042ae018 <+28>: ubfx x9, x9, #0, #32
//判断x9 和 0x8的大小(cmp指令在上一篇中有讲过)此时的0x8是最大的case与最小的case的差值
//如果 `a` 与最小的case的差值(假定为“N”),比最大的case与最小的case的差值(假定为“M”)小,说明`a` 在最大的case 和 最小的 case 之间。
//所以此时不能跳转 `default`,要进行查表,具体怎么查表我们接着往下看
0x1042ae01c <+32>: cmp x9, #0x8 ; =0x8
//将`x9`里的值写入`sp`对应的地址中
0x1042ae020 <+36>: str x9, [sp]
//无符号大于的判断,根据上面的结果,此时不会跳转`default`,所以接着往下走。(`default`对应的是`0x1042ae080`)
0x1042ae024 <+40>: b.hi 0x1042ae080 ; <+132> at main.m
不跳转default
,汇编代码接着往下执行:
//在执行下面的代码之前,`x8` 里面的值是 "5",是`a`与最小的case的差值
//下面两行代码就不做过多的解释,在上一篇完整中有过详细的解析
//最终`x8`的值是 "0x00000001042ae098"
0x1042ae028 <+44>: adrp x8, 0
0x1042ae02c <+48>: add x8, x8, #0x98 ; =0x98
//将`sp`里面对应的地址里面的值取出来,给到`x11`。那么此时x11里面的值就是 “5”;注意上面的 'mov x9, x8'
0x1042ae030 <+52>: ldr x11, [sp]
//将x11里面的值左移2位,得到的结果与x8相加,再得到的结果赋值给x10。
//这句代码的作用就是为了拿到 “表” 中对应的偏移量(偏移量是一个负数,我们下面会讲到)
//执行结果:`x10 = 0xffffffffffffffe8`
0x1042ae034 <+56>: ldrsw x10, [x8, x11, lsl #2]
//x8与x10相加,结果赋值给x9,此时x8存储的是表头的地址,表头加上偏移量,就能得到对应的case的地址
//执行结果:`x9 = 0x00000001042ae080`
//0x1042ae080 对应的是`default`的地址
0x1042ae038 <+60>: add x9, x8, x10
//跳转到x9里面的地址对应的位置
0x1042ae03c <+64>: br x9
这里我们会注意到,此时func
函数栈的结尾是:
0x1042ae094 <+152>: ret
而此时`x8`的值是 `0x1042ae098`,由此可以断定,编译器给我们生产的`差值的表`,紧挨着函数调用栈。这样印证了我们最开始讲到的`表`的情况。
![](https://img.haomeiwen.com/i1621748/3e64eff3656b3556.png)
可以看到表里面的都是
负数
,因为栈顶是大地址,栈底是小地址。
Tips
-
指针
我们都知道,指针
是占8个字节的。那么指针的自增自减又是怎样的呢?
指针
的自增自减和指针指向的对象
有关系,并且还和编译器
有关系。
int
char
-
编译优化
在Xcode中我们可以设置编译优化,这样在生成汇编代码的时候,编译器会根据我们选在的优化等级来进行相应的优化:
编译优化等级
网友评论