zoukankan      html  css  js  c++  java
  • 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.

      

      

      

  • 相关阅读:
    Kotlin中Range与异常体系剖析
    @RequestParam与@PathVariable的区别
    thymeleaf:局部变量 th:with
    关于thymeleaf th:replace th:include th:insert 的区别
    MockHttpServletRequestBuilder中content和param的区别
    使用spring的JavaMailSender发送邮件
    Spring的注解@Qualifier小结
    MySql 中 case when then else end 的用法
    @Transient 理解
    Vue生命周期-手动挂载理解
  • 原文地址:https://www.cnblogs.com/doudouyoutang/p/9263046.html
Copyright © 2011-2022 走看看