switch case 跳转表

一、事情来源

  事情来源是一段奇怪的代码,代码如下

    int x = 1000;
    switch (x) {
        case 1000:
        {
            NSLog(@"%d", 1);
        }
        case 2000:
        {
            NSLog(@"%d", 2);
        }
            break;
        case 3:
            NSLog(@"%d", 3);
            break;
        default:
            NSLog(@"%d", -1);
        case 4:
            NSLog(@"%d", 4);
            break;
        case 5:
            NSLog(@"%d", 5);
            break;
    }

  当 x = 1000的时候,代码输出的是 1和2 ,也就是 1000 和 2000的case都执行了。(测试环境是Xcode + Mac iphone 模拟器)

  原因是什么?为什么不是和if else if else一样呢

  根据网上的资料,VC6.0的编译器在case数量小于3个的时候,会使用类似if else if else的语句,

  也就是这个case不加break语句的时候,进入下一条case的时候依然需要判断条件。

  当case数量较多的时候,编译器为了优化性能,会产生一个表,表的地址就是case的汇编入口,每个case完了之后下面接着是一个break语句,jump到switch case结束的地方

  如果你的case忘记了break语句,那么很可能继续执行到下一个case,因为所有case的指令都是平铺的,知道运行到break

  那么在iOS的设备上,不管你是几条指令,编译器都会使用跳转表的方式实现。

  比如下面的代码的汇编指令:

    int x = 1;
    switch (x) {
        case 1:
        {
            NSLog(@"%d", 1);
        }
        case 2:
        {
            NSLog(@"%d", 2);
        }
        case 3:
            NSLog(@"%d", 3);

        case 4:
            NSLog(@"%d", 4);
            break;
        case 5:
            NSLog(@"%d", 5);
            break;
        default:
            NSLog(@"%d", -1);
    }

对应汇编

0x10da4361a <+58>:  movl   -0x24(%rbp), %eax
    0x10da4361d <+61>:  decl   %eax
    0x10da4361f <+63>:  movl   %eax, %esi
    0x10da43621 <+65>:  subl   $0x4, %eax
    0x10da43624 <+68>:  movq   %rsi, -0x30(%rbp)
    0x10da43628 <+72>:  movl   %eax, -0x34(%rbp)
    0x10da4362b <+75>:  ja     0x10da436bd               ; <+221> at ViewController.m
    0x10da43631 <+81>:  leaq   0xa4(%rip), %rax          ; -[ViewController viewDidLoad] + 252
    0x10da43638 <+88>:  movq   -0x30(%rbp), %rcx
    0x10da4363c <+92>:  movslq (%rax,%rcx,4), %rdx
    0x10da43640 <+96>:  addq   %rax, %rdx
    0x10da43643 <+99>:  jmpq   *%rdx
    0x10da43645 <+101>: leaq   0x1a14(%rip), %rax        ; @"%d"
    0x10da4364c <+108>: movl   $0x1, %esi
    0x10da43651 <+113>: movq   %rax, %rdi
    0x10da43654 <+116>: movb   $0x0, %al
    0x10da43656 <+118>: callq  0x10da43a14               ; symbol stub for: NSLog
    0x10da4365b <+123>: leaq   0x19fe(%rip), %rax        ; @"%d"
    0x10da43662 <+130>: movl   $0x2, %esi
    0x10da43667 <+135>: movq   %rax, %rdi
    0x10da4366a <+138>: movb   $0x0, %al
    0x10da4366c <+140>: callq  0x10da43a14               ; symbol stub for: NSLog
    0x10da43671 <+145>: leaq   0x19e8(%rip), %rax        ; @"%d"
    0x10da43678 <+152>: movl   $0x3, %esi
    0x10da4367d <+157>: movq   %rax, %rdi
    0x10da43680 <+160>: movb   $0x0, %al
    0x10da43682 <+162>: callq  0x10da43a14               ; symbol stub for: NSLog
    0x10da43687 <+167>: leaq   0x19d2(%rip), %rax        ; @"%d"
    0x10da4368e <+174>: movl   $0x4, %esi
    0x10da43693 <+179>: movq   %rax, %rdi
    0x10da43696 <+182>: movb   $0x0, %al
    0x10da43698 <+184>: callq  0x10da43a14               ; symbol stub for: NSLog
    0x10da4369d <+189>: jmp    0x10da436d3               ; <+243> at ViewController.m:66
    0x10da436a2 <+194>: leaq   0x19b7(%rip), %rax        ; @"%d"
    0x10da436a9 <+201>: movl   $0x5, %esi
    0x10da436ae <+206>: movq   %rax, %rdi
    0x10da436b1 <+209>: movb   $0x0, %al
    0x10da436b3 <+211>: callq  0x10da43a14               ; symbol stub for: NSLog
    0x10da436b8 <+216>: jmp    0x10da436d3               ; <+243> at ViewController.m:66
    0x10da436bd <+221>: leaq   0x199c(%rip), %rax        ; @"%d"
    0x10da436c4 <+228>: movl   $0xffffffff, %esi         ; imm = 0xFFFFFFFF 
    0x10da436c9 <+233>: movq   %rax, %rdi
    0x10da436cc <+236>: movb   $0x0, %al
    0x10da436ce <+238>: callq  0x10da43a14               ; symbol stub for: NSLog

  可以看到输出1,2,3 的case下面都没jmp指令;case 4的时候,会出现jump指令,也就是上面的代码是采用跳转表进行优化的。

  回到最开始的代码,如果如数的x = 30的时候,会输出多少呢?

    int x = 1000;
    switch (x) {
        case 1000:
        {
            NSLog(@"%d", 1);
        }
        case 2000:
        {
            NSLog(@"%d", 2);
        }
            break;
        case 3:
            NSLog(@"%d", 3);
            break;
        default:
            NSLog(@"%d", -1);
        case 4:
            NSLog(@"%d", 4);
            break;
        case 5:
            NSLog(@"%d", 5);
            break;
    }

  会走到default分支,输出-1;然后走到下面4的case,输出4.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值