switch

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);

复制代码

WeChat5e4ac6b0a7646b2004dc9a0bb2108f2c.png

WeChat8ab3dfbb5575aa1a7c2487ad905cc0d2.png

WeChat0d6c6ed9e002ecdd618af4b46644eab1.png

修改一下测试代码 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);
复制代码

WeChatc93c0bcbe5fc7adb712ea65f7b0c5df9.png

WeChatb1c91a5dc28411340d57d1a3081985ca.png

WeChat6f47bebf7f00423174b4a08ac6ed0d58.png

WeChat4b1d1f706f851115c23801a9d7bb022b.png

WeChatcd47189752956938c4e39ecee304856e.png

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);

复制代码

WeChat24d3fbfee2da587b01481309c0bdedbc.png

WeChatc76fdccd030c4c2d1b44cad763747063.png

WeChata7f5535ece00fa127abc16429a08140f.png

WeChat2e76dab9c9a911bd5f2bed56646a640c.png

WeChat6aa33604bf7338baefb53845817009e2.png

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

WeChatbc80b46d595d2fe8ef1812a323354b36.png

WeChat4762d6cf663784f85229f96ab9915752.png

WeChat2aa7f6ef9f21ded9a42ab5fdf5f7478d.png

WeChat3bdf57bcd3fbae16fc2027d3a6eac4b6.png

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

WeChat2f59f4073609d46f59c0c1e6541d3ce3.png

WeChat42b7c8110ab399be875a44380e256100.png

WeChat34f2015e5d09c08c65dce4ced8b32801.png

WeChat103a78e4f994e5fe740349615daa4ec2.png

WeChata4163aa40304e64cacf6c786e6f81b80.png

WeChat05ffb76b0fa7669d8bc368d3468454f5.png

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

WeChat5c23d65627bd680a0f271a24a45283bb.png

WeChat96c2cf9407e15a9c3c2ce3feeaf876c4.png

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

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

WeChat02c1019fa2a0770d599621cae806a5d3.png

WeChata1e9be4d260e91ea9e6dad957c6c05b7.png

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

WeChat868b2e17ecc5dad68d406e9a28ec1090.png

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]

WeChat14b2a5ae2307fbe986fcdcb091baff41.png

WeChat6179c47c0a04813111de848f1d8e6f7c.png

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

WeChat9a3a1adaf420910049a526b88b2ecc14.png

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

WeChat0d8461cfb0b8610ae2c6c0f4a4ab857e.png

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);

复制代码

WeChat743c18993afbac2d01f51ab1bccae619.png

WeChata6e0c67a48a1bff97a05d92fc493d0b3.png

  • 如果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);

复制代码

WeChat447a04d4bdbf29ee3053037545e501f4.png

br指令

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

编译器的优化

编译器的优化等级

16205455785252.png

测试代码

#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]));
}

复制代码

没有优化

WeChatfeacddbdf22a9e594b59d6d0306f6465.png

修改debug的优化配置

WeChat2c825758ab451504c4fc9a6633f5f9f5.png

临时变量a和b不见了

WeChatd2efb14ef784e273bea6fc5a65b37655.png

再次修改测试代码 调用了一个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]));
}
复制代码

WeChat1bc0373458fc952fe9b2c55cc991b621.png

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

再修改一次测试代码,将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]));
}
复制代码

WeChatad1c6bdfee10856436bc34221373744e.png

指针

sizeof

测试代码

void func() {
    int *a;
    printf("%lu", sizeof(a));
}

int main(int argc, char * argv[]) {
    func();
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}

复制代码

WeChatf76aeca18943127af5de605a57105a30.png

指针的自增和自减

测试代码

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]));
}

复制代码

WeChatb3fa04109d7a9fe85cfcb3cfc49e8e1d.png

  • 指针的自增和自减和执行的数据类型的宽度相关 上面的例子中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]));
}

复制代码

WeChat46bddf26045c5191d89e9c610ed03b06.png

测试代码

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]));
}

复制代码

WeChatf6fd3a409c650479be4720cb21cf8893.png

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]));
}

复制代码

WeChatdd2d841bdf84481239c2d9b43cac82b7.png

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

指针的反汇编

测试代码

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]));
}

复制代码

WeChat98ae78873f9a5fe91c8d48eceffeab90.png

数组测试代码

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]));
}
复制代码

WeChat9b3481495babc999948e6c861044b5a9.png

WeChat4a3edbb83348dad1e31234b071810330.png

测试代码 空指针加偏移量 偏移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]));
}

复制代码

WeChat084f0744807e37474cd09890489be78e.png

测试代码 空指针加偏移量 偏移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]));
}

复制代码

查看反汇编代码

WeChat9696644881e352f872b2f881d477738e.png

将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]));
}

复制代码

WeChat390310b3d4f57f83314813aecb7dc332.png

将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]));
}

复制代码

WeChat8f027ee39e1aafd32378a31a6d60f944

指针的多级指针

void func() {
    char **p1;
    char c = **p1;
    
    printf("hello");
}

int main(int argc, char * argv[]) {
    func();
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}

复制代码

WeChat863adef8b27adb5b9bcac64dcb68cd64.png

指针的多级指针 + 偏移量

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]));
}

复制代码

WeChat4d992c454499ec49bf569dd81d973ce2.png

使用索引

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]));
}
复制代码

反汇编代码

WeChat717eb47cc696a149e869be8b5b1a6bb5.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享