• 注册
  • iOS博客 iOS博客 关注:0 内容:64

    switch

  • 查看作者
  • 打赏作者
  • 当前位置: 职业司 > iOS开发 > iOS博客 > 正文
    • iOS博客
    • 男神

      Switch

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

      switch 测试代码 1

      int funcA(int a) {
      switch (a) {
      case 1:
      printf("打坐");
      break;
      case 2:
      printf("加红");
      break;
      case 3:
      printf("加蓝");
      break;
      case 5:
      printf("打怪");
      break;
      default:
      printf("什么都不干");
      break;
      }
      return 0;
      }
      funcA(4);
      复制代码

      switch

      switch

      switch

      修改一下测试代码 2

      int funcA(int a) {
      switch (a) {
      case 5:
      printf("打坐");
      break;
      case 6:
      printf("加红");
      break;
      case 7:
      printf("加蓝");
      break;
      case 8:
      printf("打怪");
      break;
      default:
      printf("什么都不干");
      break;
      }
      return 0;
      }
      funcA(4);
      复制代码

      switch

      switch

      switch

      switch

      switch

      0x1004a20b8 <+28>: ubfx x9, x9, #0, #32这句命令的含义是: 将寄存器x9的值,从高位0位开始,向后面32位开始清0,并将结果保存到x9寄存器中 也就是高32位清零

      • #0 是起始位置
      • #32 是范围
      • 后面的x9, #0, #32是将x9高32位清零
      • 最后将 x9 保存到x9

      测试代码 3

      int funcA(int a) {
      switch (a) {
      case 4:
      printf("打坐");
      break;
      case 6:
      printf("加红");
      break;
      case 7:
      printf("加蓝");
      break;
      case 8:
      printf("打怪");
      break;
      default:
      printf("什么都不干");
      break;
      }
      return 0;
      }
      funcA(5);
      复制代码

      switch

      switch

      switch

      switch

      switch

      x8寄存器指向的是地址,里面存储的是一堆负数

      switch

      switch

      switch

      switch

      0x1000720ac <+20>: subs w8, w8, #0x4这句指令减去的0x4是怎么来的?

      switch

      switch

      switch

      switch

      switch

      switch

      • 从前面的三个例子,可以看出, subs w8, w8, #0x4 这句指令后面减去的值,是case的最小值

      switch

      switch

      1. 减去最小的case值,保存到x9
      2. 如果不在区间内,跳转到default,否则继续执行。x9 - 最大区间
      3. 通过表拿到地址

      PS:为什么是b.hi 无符号大于
      如果传入的a=1,subs执行之后,x9中保存的是负数,肯定不在区间之内。负数在无符号运算中,是一个非常大的数字,就会超过case的范围, 就会跳转到default中。

      switch

      switch

      PS: 表中保存的负数的个数 = case的最到值 - case的最小值 + 1(default)

      switch

      case的查询表

      • case2: -96 [x8 + 4]
      • default: -32 [x8 + 8]
      • default: -23 [x8 + 12]
      • default: -23 [x8 + 16]
      • case6: -80 [x8 + 20]
      • case7: -64 [x8 + 24]
      • case8: -48 [x8 + 28]

      switch

      switch

      switch case的代码是连续的 通过上面的表 找到case

      switch

      PS: ldrsw x10, [x8, x11, lsl #2] 为什么是左移两位,即偏移4

      switch

      PS: 表中为什么存储的是地址的差值,不是地址

      • 地址是8个字节, 差值是4个字节,节省空间
      • 最重要的一点, 地址在运行的时候才会知道虚拟地址, 如果存储地址,仍然需要加上ASLR

      PS: 如果case很大,是什么情况?

      • 如果case很大,只要case是连续的就可以

      例如将代码修改

      int funcA(int a) {
      switch (a) {
      case 102:
      printf("打坐");
      break;
      case 106:
      printf("加红");
      break;
      case 107:
      printf("加蓝");
      break;
      case 108:
      printf("打怪");
      break;
      default:
      printf("什么都不干");
      break;
      }
      return 0;
      }
      funcA(105);
      复制代码

      switch

      switch

      • 如果case很大,case不是连续的 编译器就会优化

      代码修改为

      int funcA(int a) {
      switch (a) {
      case 2:
      printf("打坐");
      break;
      case 406:
      printf("加红");
      break;
      case 807:
      printf("加蓝");
      break;
      case 8:
      printf("打怪");
      break;
      default:
      printf("什么都不干");
      break;
      }
      return 0;
      }
      funcA(105);
      复制代码

      switch

      br指令

      br x9 跳转到x9寄存器里面的值 r是寄存器的意思 影响x30寄存器

      编译器的优化

      编译器的优化等级

      switch

      测试代码

      #import <UIKit/UIKit.h>
      #import "AppDelegate.h"
      int main(int argc, char * argv[]) {
      int a = 1;
      int b = 2;
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      没有优化

      switch

      修改debug的优化配置

      switch

      临时变量a和b不见了

      switch

      再次修改测试代码 调用了一个sum方法

      int sum(int a, int b) {
      return a + b;
      }
      int main(int argc, char * argv[]) {
      int a = sum(1, 2);
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      switch

      编译器对执行结果没有影响的代码,会被优化掉

      再修改一次测试代码,将sum的结果打印出来

      int sum(int a, int b) {
      return a + b;
      }
      int main(int argc, char * argv[]) {
      int a = sum(1, 2);
      NSLog(@"%d", a);
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      switch

      指针

      sizeof

      测试代码

      void func() {
      int *a;
      printf("%lu", sizeof(a));
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      switch

      指针的自增和自减

      测试代码

      void func() {
      int *a;
      a = (int *)100;
      a++;
      printf("%lu",a);
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      switch

      • 指针的自增和自减和执行的数据类型的宽度相关 上面的例子中int的宽度是4个字节,所以是104 = 100 + 4

      修改测试代码

      void func() {
      int **a;
      a = (int **)100;
      a++;
      printf("%lu",a);
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      switch

      测试代码

      void func() {
      char *a;
      a = (char *)100;
      a++;
      printf("%lu",a);
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      switch

      PS: 自增和自减和编译器有关
      PS: a = a + 1;a += 1;a++;三个是一样的

      指针的运算

      void func() {
      int *a;
      a = (int *)100;
      int *b;
      b = (int *)100;
      int x = b - a;
      printf("%lu",x);
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      switch

      • 指针运算的单位是指向数据类型的宽度
      • 加减乘除都是以指向数据类型的宽度为单位
      • 指针可以比较大小
      • 指针是可以强制转换的,但是结构体和基本类型是不可以强制转换的

      指针的反汇编

      测试代码

      void func() {
      int *a;
      int b = 10;
      a = &b;
      printf("hello");
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      switch

      数组测试代码

      void func() {
      int arr[5] = {1, 2, 3, 4, 5};
      for (int i = 0; i < 5; i++) {
      printf("%d\n",*(arr  + i));
      }
      printf("hello");
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      PS: int *a = &arr[0] = arr 这几个是对等的关系

      void func() {
      int arr[5] = {1, 2, 3, 4, 5};
      int *a = arr;
      for (int i = 0; i < 5; i++) {
      //        printf("%d\n",*(arr  + i));
      printf("%d\n",*(a++));
      }
      printf("hello");
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      测试代码 空指针

      void func() {
      char *p;
      char p1 = *p;
      printf("hello");
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      switch

      switch

      测试代码 空指针加偏移量 偏移0

      void func() {
      char *p;
      char p1 = *p;
      char d = *(p + 0);
      printf("hello");
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      switch

      测试代码 空指针加偏移量 偏移1

      void func() {
      char *p;
      char p1 = *p;
      char d = *(p + 1);
      printf("hello");
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      查看反汇编代码

      switch

      将char类型改为int类型

      void func() {
      int *p;
      int p1 = *p;
      int d = *(p + 1);
      printf("hello");
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      switch

      将char类型改为指针类型

      void func() {
      int **p;
      int *p1 = *p;
      int *d = *(p + 1);
      printf("hello");
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      指针的多级指针

      void func() {
      char **p1;
      char c = **p1;
      printf("hello");
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      switch

      指针的多级指针 + 偏移量

      void func() {
      char **p1;
      char c = *(*(p1 + 2) + 2); //**p1;
      printf("hello");
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      switch

      使用索引

      void func() {
      char **p1;
      char c = p1[1][2];
      printf("hello");
      }
      int main(int argc, char * argv[]) {
      func();
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
      复制代码

      反汇编代码

      switch

      请登录之后再进行评论

      登录

      手机阅读天地(APP)

      • 微信公众号
      • 微信小程序
      • 安卓APP
      手机浏览,惊喜多多
      匿名树洞,说我想说!
      问答悬赏,VIP可见!
      密码可见,回复可见!
      即时聊天、群聊互动!
      宠物孵化,赠送礼物!
      动态像框,专属头衔!
      挑战/抽奖,金币送不停!
      赶紧体会下,不会让你失望!
    • 实时动态
    • 签到
    • 做任务
    • 发表内容
    • 偏好设置
    • 到底部
    • 帖子间隔 侧栏位置:
    • 还没有账号?点这里立即注册