Switch
- 假设switch语句分支比较少的时候(例如3,少于4的时候没有意义) 没有必要使用此结果,相当于if
- 各个分支的常量的差值较大的时候, 编译器会在效率还是在内存进行取舍, 这个时候编译器还是会编译成类似if、else的结果
- 在分支比较多的时候: 在编译的时候会生成一个表(跳转表每个地址四个字节)
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);
复制代码
修改一下测试代码 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);
复制代码
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);
复制代码
x8寄存器指向的是地址,里面存储的是一堆负数
0x1000720ac <+20>: subs w8, w8, #0x4这句指令减去的0x4是怎么来的?
- 从前面的三个例子,可以看出, subs w8, w8, #0x4 这句指令后面减去的值,是case的最小值
- 减去最小的case值,保存到x9
- 如果不在区间内,跳转到default,否则继续执行。x9 – 最大区间
- 通过表拿到地址
PS:为什么是b.hi 无符号大于
如果传入的a=1,subs执行之后,x9中保存的是负数,肯定不在区间之内。负数在无符号运算中,是一个非常大的数字,就会超过case的范围, 就会跳转到default中。
PS: 表中保存的负数的个数 = case的最到值 – case的最小值 + 1(default)
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 case的代码是连续的 通过上面的表 找到case
PS: ldrsw x10, [x8, x11, lsl #2] 为什么是左移两位,即偏移4
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);
复制代码
- 如果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);
复制代码
br指令
br x9 跳转到x9寄存器里面的值 r是寄存器的意思 影响x30寄存器
编译器的优化
编译器的优化等级
测试代码
#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]));
}
复制代码
没有优化
修改debug的优化配置
临时变量a和b不见了
再次修改测试代码 调用了一个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]));
}
复制代码
编译器对执行结果没有影响的代码,会被优化掉
再修改一次测试代码,将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]));
}
复制代码
指针
sizeof
测试代码
void func() {
int *a;
printf("%lu", sizeof(a));
}
int main(int argc, char * argv[]) {
func();
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
复制代码
指针的自增和自减
测试代码
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]));
}
复制代码
- 指针的自增和自减和执行的数据类型的宽度相关 上面的例子中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]));
}
复制代码
测试代码
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]));
}
复制代码
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]));
}
复制代码
- 指针运算的单位是指向数据类型的宽度
- 加减乘除都是以指向数据类型的宽度为单位
- 指针可以比较大小
- 指针是可以强制转换的,但是结构体和基本类型是不可以强制转换的
指针的反汇编
测试代码
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]));
}
复制代码
数组测试代码
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]));
}
复制代码
测试代码 空指针加偏移量 偏移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]));
}
复制代码
测试代码 空指针加偏移量 偏移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]));
}
复制代码
查看反汇编代码
将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]));
}
复制代码
将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]));
}
复制代码
指针的多级指针 + 偏移量
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]));
}
复制代码
使用索引
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]));
}
复制代码
反汇编代码