C语言基础之麻辣香锅

C语言基础之麻辣香锅

Wirte by 021. Leave a message if i messed up ! : )

汇编语言入门教程- 阮一峰的网络日志

家常菜之 — C基础语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
//
// main.c
// Assembly
//
// Created by 021 on 2020/11/14.
//







#include <stdio.h>
#include<string.h>
#include <stdlib.h> //找包含文件目录
#include "add.cpp" //找当前目录,


//int myOperation(int a, int b);


int mySwitch(int a)
{
switch(a){
case 1: printf("Monday\n"); break;
case 2: printf("Tuesday\n"); break;
case 3: printf("Wednesday\n"); break;
case 4: printf("Thursday\n"); break;
case 5: printf("Friday\n"); break;
case 6: printf("Saturday\n"); break;
case 7: printf("Sunday\n"); break;
case 8: printf("8\n"); break;
case 9: printf("9\n"); break;
case 10: printf("10\n"); break;
default:printf("error\n"); break;
}
return 0;
}


int myGoto(int a)
{
int b = 1;
A : // 0x00001234 内存地址

b++;
printf("b =%u\n",b);
if(b<a)
{
goto A; // jmp 0x00001234; 直接跳转,重复执行
}
printf("goto循环结束 =%u\n",b);
return b;
}

int myWhile(int a)
{

int b = 1;
while(b<a)
{
printf("while循环中 b =%u\n",b);
b++;

if(a==2)
{
continue;
printf("a=2 被continue跳过了,不会打印",b);
}

}
printf("while循环结束 =%u\n",b);
return b;
}

int myDoWhile(int a){
int b = 1;
do // 0x0000 0001;
{
printf("do while循环开始 =%u\n",b);
b++;
}
while (b<=a); // 判断 , 条件符合 jmp 0x0000 0001;

printf("do while循环结束 =%u\n",b);
return b;
}

int myFor(int a)
{
int b = 1;
int c;
int d;
//for(表达式1不要求有返回值;表达2要求有返回值,不是0就成立;表达式3不要有返回值)
for(c = 0,d =2;b<a;b++,c++,d++)
{
printf("for循环 =%u\n",b);
}
printf("for循环结束 =%u\n",b);
return b;
}
void arrayOverStackTest()
{
for(;;)
{
printf("arrayOverStackTest");
}
}


int myArrayOverStack(int array[])
{
array[6]=(int)&arrayOverStackTest;
return 0;
}

int methodAgrTest(int a)
{
return a+1;
}

int methodArrAgrTest(int a[])
{
return a;
}

void arrayTest(int a[],int size)
{
for(int i =0; i<size;i++)
{
printf("数组传参传的是数组第一个元素的地址,遍历元素值= %p\n",&a[i]);
printf("数组传参传的是数组第一个元素的地址,遍历元素值= %p\n",*(&a[i]));

}
}

void arrayPointTest(int* a,int size)
{
for(int i =0; i<size;i++)
{
printf("数组指针传参传的是数组第一个元素的地址,遍历元素值= %d\n",*(a+i));
}
}

int __cdecl my_cdecl(int a,int b)
{
return a+b;
};

int __stdcall my_stdcall(int a,int b)
{
return a+b;
};

int __fastcall my_fastcall(int a,int b)
{
return a+b;
};



struct myStruct
{
char c;
short s;
int i;
};

struct my8byteStruct
{
char c;
short s;
double i;
};


struct myPoint
{

char a;

};

struct myPointSize
{

double b;
double b1;
double b2;

};



//自定义数据宽度对齐
#pragma pack(2)
struct myPragmaStruct
{
char c;
int i;
double d;
};
#pragma pack()

#pragma pack(2)
struct person
{
char age;
char name[0x14];
};
#pragma pack()

#define name1 "021"
#define true 1
#define false 0
#define hello1 "你好,"
#define mystr strcpy(hello1,name1)



int main(int argc, const char * argv[]) {


//整型
//-128 --- signed --- 0 --- unsigned --- 127;
char c = 'a'; //1byet 0xff
short s = 0xffff; // 2byte 0xffff
int i = 0xffffffff; //4byte
long l = 0xffffffff; //4byte
printf("char : %c %d\n",c,c);
printf("short : %c %d\n",s,s);
printf("int i 无符号: %u int i 有符号: %d\n",i,i);

/**
*
*符号表示 , 编译器只关注数值存储,取数时有无符号有区别;默认有符号;
*大部分计算机只存补码, 符号位将影响取值和判断.
*/
signed char sc = -1; // 1111 1111 0xff; 0000 0001 %u = 4294967295
unsigned char usc = -1; // 补码+1 = 1111 1111 , 0xff
unsigned char usc1 = -2; // 0000 0010 -> 1111 1101 + 1 -> 1111 1110 -> 0xfe;
printf("sc有符号=%d,转换成无符号=%u\n",sc,(unsigned char)sc);
printf("sc 无符号数(扩展错误数值) : %u\n",sc); //此时取值可能进行了扩展 ,%u = 4294967295
//有无符号之间转换
printf("无符号usc=%u,无符号转有符号usc=%d\n",usc,(char)usc);

/**
*数据宽度扩展:低位为数据位, 高位为符号位
*/
//将有符号8位char类型放入32位int类型,
int i1 = sc; // 1111 1111 -> 0xffffff + 1111 1111 = 0xffffffff;
printf("有符号sc数据扩展int=%u,无符号转有符号=%d\n",i1,(int)i1);


/**
*数据宽度溢出
*溢出的值为正的:实际值为:溢出后的值 - 该类型能表示的立即数
*溢出的值为负的:实际值为:溢出后的值 + 该类型能表示的立即数
*其中-0的原码是: 1000 0000 补码是:1 0000 0000 = 128的由来,+0 -0有点无厘头
*/
//默认有符号,0xff的数据区间:有符号最小值:1111 1111 = -0x7f=-127; 最大值:0111 1111 = 0x7f =127;
char sc1 = 256; //将256存入 -127 — 127数据宽度区间 发生溢出
printf("数据宽度溢出sc1=%u\n",sc1); //256- 1111 1111 = 0;
char sc2 = -258;
printf("数据宽度溢出sc2=%d\n",sc2); //-257 + 1111 1111 = -2;



/**
*浮点类型
*float 1位(符号位) 8位(整数位) 23位(尾数位)
*double 1位(符号位) 11位(整数位) 52位(尾数位)
*/
float f = 123.25f; // 0xffffffff;
double d = 22.22; // 0xffffffff ffffffff;;
printf("浮点数f=%f\n",f); //-257 + 1111 1111 = -2;
printf("有符号sc数据扩展int=%u",0xffffffac);




//Switch
mySwitch(6);

//循环goto
myGoto(3);

//循环while
myWhile(3);

//循环doWhile
myDoWhile(5);

//循环for
myFor(5);

//数组
int array[5]; // 不赋值,堆栈也默认会提升;
int array1[5] = {1,2,3,4,5}; // mov dword [ebp+4], 0x01;
char charArray[10] ; //本机宽度 ,内存对齐, 32位 4byte对齐, 64位 8byte对齐;
short shortArray[10] ; //本机宽度 ,内存是对齐,

//数组越界
myArrayOverStack(array1);

/**
*多维数组 , 一个班2个组,一个组5个人 //内存分布与一维数组一样
*内存中数据被打平存储 : 1,2,3,4,5, 5,4,3,2,1
*索引 array[2][3] = array[(2-1)*5+3] 算法
*/
int array2[2][5] =
{
{
1,2,3,4,5
},
{
5,4,3,2,1
}
};

//结构体/自定义类型, 未赋值之前不占用任何内存空间.
//结构体为全局变量时占用空间
struct myStruct ms = {1,2,3};
printf("结构体属性值 c=%u\n",ms.c);

/**
* ---------------- 字节对齐 ---------------
* 全局变量, char c; int z; 变量内存地址是变量类型宽度的整数倍;
* 以类型宽度最大的为准,上述以int为准,int 类型4byte,那么内存地址是4的整数倍;
*
*/
printf("结构体属性c数据宽度=%u\n",sizeof(ms.c));
printf("结构体属性s数据宽度=%u\n",sizeof(ms.s));
printf("结构体数据宽度=%u\n",sizeof(ms));

struct my8byteStruct m8s = {1,2,3}; //大尺寸对象
printf("结构体m8s属性c数据宽度=%u\n",sizeof(m8s.c));
printf("结构体m8s属性s数据宽度=%u\n",sizeof(m8s.s));
printf("结构体m8s数据宽度=%u\n",sizeof(m8s));

/**
*改变结构体数据宽度对齐
*/
struct myPragmaStruct mps = {1,2,3}; // 压缩结构体尺寸,
printf("结构体mps属性c数据宽度=%u\n",sizeof(mps.c));
printf("结构体mps属性i数据宽度=%u\n",sizeof(mps.c));
printf("结构体mps属性s数据宽度=%u\n",sizeof(mps.d));
printf("结构体mps数据宽度=%u\n",sizeof(mps));

//结构体数组
struct person p[2];
p[0].age = 0x12;
stpcpy(p[0].name,"021");
printf("结构体person属性c数据值= %d\n",p[0].age);
printf("结构体person属性name数据值= %s\n",p[0].name);

/**
*指针类型 :
*多星的时候恒定数据宽度为4= char** cp ,一星的 char* cp 数据宽度=指针类型的宽度;
*指针类型运算时以 指针类型的数据宽度为基数自增
*指针无符号
*
*/
char* cp ; //char******* cp ;
int* ip ;
short* sp ;
cp = (char*)100;
ip = (int*)100;
sp = (short*)100;
struct person* p1;
printf("指针类型person数据值= %p\n",p1);
printf("指针类型cp数据值= %d\n",cp);
cp++;
ip++;
sp++;
//指针类型不能做乘法和除法
//sp*1;
printf("char指针类型cp自增后数据值= %d, 数据宽度=%d\n",cp,sizeof(cp));
printf("int指针类型ip自增后数据值= %d\, 数据宽度=%d\n",ip,sizeof(ip));
printf("short指针类型sp自增后数据值= %d\, 数据宽度=%d\n",sp,sizeof(sp));

//指针类型比较
if(ip>cp)
{
printf("指针类型比较后数据值= %d\n",ip);
}

/**
* 取地址符 & , 只能和变量用
* lea指令=将局部变量地址获取
*/
printf("取地址符 '&' ,sp地址值= %p\n",&sp);
//类型不匹配 能过编译,执行不生效
int ip1 = &cp;
printf("取地址符 '&' ,ip1地址值= %p cp=%p\n",&ip1,&cp);
char* cp1 = &cp;
printf("取地址符 '&' ,cp1地址值= %p cp=%p\n",&cp1,&cp);

/**
* 取值运算符: '*',
* 指针取地址值符 * , 只能指针类型用
* int*** a ; *a取值会变成 = int** a;
*
*/
int* ip2 = &ip;
printf("指针取值运算符 '*' ,指针cp1存储的数据值= %d\n",*cp1);
printf("指针取值运算符 '*' ,指针ip2存储的数据值= %d\n",*ip2);

int i2 = 1;
int* ip3 = &i2;
printf("指针地址取值'&' 地址值=%p ,指针取值运算符 '*' ,指针cp1存储的数据值= %d\n",&i2,*ip3);

/**
* 参数传递,是地址传参,还是值传参,
*/
int methodAgr = 1;
int methodAgrTestValue = methodAgrTest(methodAgr);
methodAgrTest(methodAgr);
printf("值传参还是地址传参 答案是值传递数据值= %d\n",methodAgr);
printf("值传参还是地址传参 答案是值传递数据值= %d\n",methodAgrTestValue);

/**
*数组传参
*传递的是数组首地址第一个元素 int array[2] = {1,2} ;
* mov eax , &array[1]; // 数组第一个元素的地址
* array[2] = lea dword ds:[eax+1*4] ; // 获取第二个元素是使用 第一个元素地址偏移量*4;
*
*/
int arrayTestArg[2] = {1,2};
arrayTest(arrayTestArg,2);
arrayPointTest(&arrayTestArg[0],2);


/**
* 字符串函数
*
*/
char str[3] ={'0','2','1',0}; //需要手动补0;
printf("字符串str= %s\n",str);

//先在常量区 创建'021', 再把'021'复制到数组str1[]中,进行操作;
char str1[4] = "021"; //编译器自动补0;
printf("字符串str1= %s\n",str1);
printf("字符串str1= %s\n",*(&str1));
char str2[9] = "021中国";
printf("strlen函数字符串str1长度= %d,值=%s\n",strlen(str2),&str2);
char cp3[6] ;
strcpy(cp3, "china");
printf("strcpy复制字符串cp3= %s\n",cp3);
char love[10] ;
char you[10] ;
strcpy(love, "l love");
strcpy(you, "you");
strcat(love,you);
printf("strcat拼接字符串= %s\n",love);

char love1[9];
char love2[9];
strcpy(love1, "l love");
strcpy(love2, "l love");
int stat =strcmp(love1,love2); //0相同,非0不相同;
if(!stat)
{
printf("strcmp判断字符串love1与love2相同\n");
}

/**
* 一级指针与多级指针
* 外包装*加1;
* 拆包装*减1;
*/
//包装
int ip4 = 1;
int* ip5 = &ip4;
int** ip6 = &ip5;
int*** ip7 = &ip6;
//解包装
int ip8 = *(*(*(ip7)));
printf("多级指针 ip8=%d\n",ip8);
printf("多级指针 ip7=%d\n",***ip7);

/**
* 结构体指针 数据宽度恒定4字节
*
*/
struct myPoint mp;
struct myPoint* mp1 = &mp; //类型对齐
printf("结构体指针数据宽度 mp1=%lu\n",sizeof(mp1));

//赋值
mp1->a = 21;
printf("结构体指针获取数据值mp1.a=%d\n",mp1->a);

//数组指针指向结构体指针 数据宽度恒定4字节
int arr[3] ={1,2,3};
struct myPoint* mp2 = (struct myPoint*)&arr; //指针类型强转
printf("结构体指针获取数据值mp2.a=%d\n",mp2->a);


/**
* 指针数组与数组指针
*/
//指针数组 数据宽度恒定4字节
char arr2[10];//20byte
char* arr3[10]; //40byte 10指针(10* char*);
struct myPoint* arr4[10]; //40byte 10指针(10* myPoint*);

char* c2 = "china"; //将china字符串常量内存地址赋值给C1;

char* c1 = "hello"; //将hello字符串常量内存地址赋值给C1;

char* c3[10] = {c1,c2};
printf("结构体指针获取数据值c3=%s\n",c3[0]);

//数组指针 数据宽度恒定4字节 , cpu位数不同指针宽度可能不同
int arr5[3] = {0,1,2};
int* arrPoint = &arr5; //数组指针,取数组里第一个元素的地址
int* arrPoint1 = ++arrPoint;
printf("结构体指针获取数据值arrPoint=%p ,指针值=%d \n",&arrPoint1,*arrPoint);

int* arrPoint2 = ++arrPoint;
printf("结构体指针获取数据值arrPoint=%p ,指针值=%d \n",&arrPoint2,*arrPoint);


/**
*函数指针—— 按照自定义方式调用目标函数;
* 使用别人写好的函数
*/
//定义函数指针,模拟自己写好的int __cdecl my_cdecl(int a,int b)函数
//自己写的函数
int result1 = my_cdecl(2,2);
printf("函数指针调用被调用函数返回结果值=%d 返回值地址=%p\n",result1,&result1);

int (__cdecl *my_cdeclCall)(int,int);

//赋值 ; 函数指针赋值执行地址,0x100002830为my_cdecl函数调用地址,此处为硬编码
//0x1000033c9 <+2873>: callq 0x100002830 ; my_cdecl at main.c:145
//my_cdeclCall = (int (__cdecl *)(int,int))0x1000027d0;

//调用函数指针
//int result = my_cdeclCall(1,2); //结果为3;
//printf("函数指针调用返回结果值=%d \n",result);



/**
* 调用公约
* _cdecl - 从右到左压栈,调用者平栈(外平栈)
* _stdcall - 从右到左压栈,函数自身平栈(内平栈)
* _fastcall - ecx edx 传送前两个参数,剩下的从右到左入栈,函数自身平栈(内平栈)
*/
int arg = 0;
int arg1 = 1;
my_cdecl(0,1);
my_stdcall(0,1);
my_fastcall(0,1);



/**
* 预处理与自定义宏
* 逻辑少的时候用宏
* 逻辑多的时候用函数
*/
// #define name1 "021"
// #define true 1
// #define false 0
// #define hello1 "你好,"
// #define mystr strcpy(hello,name)
printf("自定义宏调用返回结果值=%s \n",name1);


/**
* 条件编译与文件包含
* 条件编译主要用于调试与测试代码的管理,把测试代码不编译到源文件
*
* #undef debug //取消之前定义debug宏
* #define debug 0 //重新定义
*
* #if debug
* printf("编译后可以生成反汇编.");
* #endif
*
* #if debug
* printf("编译后不能生成反汇编.");
* #endif
*
* #if define b //如果b定义了编译
* printf("编译后可以生成反汇编.");
* #elif define a //如果a定义了编译
* printf("编译后可以生成反汇编.");
* #else define c //如果c定义了编译
* printf("编译后可以生成反汇编.");
* #endif
*
*
*
*/
//使用包含文件函数
int fileResult = myAdd(1,2);
printf("使用包含文件函数,返回结果=%d \n",fileResult);

return 0;
}



厨师长特调之 —– 浮点数

img

img

精度概要

  • 对于float型浮点数,尾数部分23位,换算成十进制就是2^23=8388608,所以十进制精度只有6 ~ 7位;

  • 对于double型浮点数,尾数部分52位,换算成十进制就是2^52 = 4503599627370496,所以十进制精度只有15 ~ 16位

* **前景概要与演练**

截屏2021-11-20 下午3.01.21

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27



// 求十进制浮点数 ,求转换 12.34
1 * 10¹ + 2*1(10零次方) + 3 * 1/10(10的负一次方)+ 4 * 1/10*10(10的负二次方)
浮点数的规范后: 1.234 * 10¹ ; 指数为1;


// 二进制浮点转十进制 ,求转换 1100.11
1 * 2*2*2(三次方) + 1 * 2*2(二次方) + 0 * 2(一次方) + 0 * 1(2的0次方) + 1 * 1/2¹ + 1 * 1/2*2(二次方)
= 8 + 4 + 0 + 0 + 1/2 + 1/4
= 12.75
浮点数的规范后: 2.475 * 10¹; 指数为1;

求 1010.01 的十进制,二进制浮点数规范后= 1.01001 * 2*2*2 指数: 3
1 * 2*2*2 + 0 * 2*2 + 1 * 2 + 0 * 2(零次方) + 0 * 1/2¹ + 1 * 1/2²
= 8 + 0 + 2 + 0 + 1/2 + 1/4
= 10.75
10进制浮点数的规范后: 1.075 * 10¹; 指数为1;

求 10101.01 的十进制,二进制浮点数规范后= 1.010101 * 2*2*2*2 指数: 4
1 * 2*2*2*2 + 0 * 2*2*2 + 1 * 2*2 + 0 * 2 + 1 * 1(2的零次方)+ 0 * 1/2 + 1 * /2*2
= 16 + 0 + 4 + 0 + 1 + 0 + 1/4
= 21.25



浮点数二进制存储表示

  • 1,确定符号位

  • 2,确定指数偏移量

  • 3,对齐小数位并补0(总共23位)

符号位
  • 0 正

  • 1 负

指数位
  • 按照127+指数偏移量得出二进制,填充进指数位,填充8位
小数位
  • 去掉 浮点规范后的 整数位,低位补0,补齐23位
1
2
3
4
5
6
7
8
9
10
求 1.125的小数位:

0.125×2=0.25 取整数位0
0.25×2=0.5 取整数位0
0.5×2=1 取整数位1

小数部分所得结果为 001;

为什么这么做, 当尾数*2=1的时候代表有进位,才能标记.

  • 那我们来测试一下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    简单点以5结尾的小数;

    求 123.25 的内存存储

    1. 首先求出二进制数(小规律,先求数据宽度区间最大数和最小数,然后依次取最大数填充,这样就不用计算器了)
    123 = 100 + 20 + 3 = 1 1 1 1 1 1 1 1 = 01?? + ?1(确定最大最小数)
    128 64 32 16 8 4 2 1

    = 64 + 3 ,还差56,继续填充 = 01 1(32) 1(16) 1(8)011 = 0111 1011; 最终整数部分;

    小数部分:结果01
    推出:
    0.25 * 2 ; 0
    0.50 * 2 ; 1

    整合: 0111 1011.01 , 浮点数规范 : 1.11 1011 01 指数为8; (错误)
    整合: 0111 1011.01 , 浮点数规范 : 1.111011 01 指数为6; (正确)




    2,定义符号位:
    正数 = 0;

    3,定义指数位:
    127 + 8 = 135 = 1000 0111(错误)
    127 + 6 = 133 = 1000 0101 (正确)



    4,定义尾数部分 ,去掉整数部分,低位补齐0,23位; 1.11101101 = 1110 1101;

    5,整合:
    0 + 1000 0111 + 1110 1101 = 0100 0011 1111 0110 1000 0000 0000 0000 = 0x43f68000; (错误)
    //纠错
    0 + 1000 0101 + 1110 1101 = 0100 0010 1111 0110 1000 0000 0000 0000 = 0x42f68000;(正确)



    // 结果 和 程序运行有误差 ... 0x42F68000 这个才是正确的,找一下问题:
    整合: 0111 1011.01 , 浮点数规范 : 1.11 1011 01 指数为8; (错误) 这里位移脑子抽了,计算失误. 还是计算机好...

    //到此 结果正确,
    0 + 1000 0101 + 1110 1101 = 0100 0010 1111 0110 1000 0000 0000 0000 = 0x42f68000;(正确)

厨师长特调之 —– Switch算法(参考数组存储)

  • 在特定区间连续条件下,switch算法会进行优化

  • switch会维护一张地址表,编译器优化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35

    模拟代码逻辑:

    int minCase = 1; 最小的条件语句

    int maxCase = 9; 最大

    int myCondition = 1;


    //最小值处理,如果小于最小值直接不符合case区间,也会直接走default;
    if(myCondition < minCase) 如果大于最大值;直接跳默认值
    {
    // Jcc跳转
    jmp default;
    }


    最大值处理,如果大于最大值直接不符合case区间,直接走default;
    if(myCondition > maxCase) 如果大于最大值;直接跳默认值
    {
    // Jcc跳转
    jmp default;
    }


    //连续case区间逻辑跳转,参数数组内存存储,编译器优化连续case,利用偏移量找位置
    if((myCondition - minCase)*4的内存地址)
    {
    如果条件为1 ; 1-1 = 0 ; 0 * 4 = 0 ;跳转到索引表第0个,一次类推,这个表的算法是编译器优化的,
    jmp addresstable;
    }



截屏2021-11-21 下午12.55.12

截屏2021-11-21 下午12.55.19

  • 在case区间大的时候 switch 无法优化

截屏2021-11-20 下午9.28.18

截屏2021-11-20 下午9.29.41