2020-11-27(switch的优化问题)

第一次看switch的case表的时候,那是半年前了,看完了有序线性然后去看非线性索引时,实在看不下去了,今天再一次拿出这本书,把switch 的 有序线性 ,非线性,以及 判断树 看了一遍,感触挺深的吧,接下来让我们一起被switch虐吧。

1.首先,二话不说,上代码,代码具有较高说服力
在这里插入图片描述

在这里插入图片描述

两份代码debug版本相比较后,大家可以发现,if……else if 结构会在条件跳转后紧跟语句块;而switch结构则将所有条件跳转都放置到了一起,并没有发现case语句的踪影。通过条件跳转指令,跳转到相应的case语句块中,因此每个case的执行是由switch比较结果引导“跳”过来的。所有的case语句块都是连在一起的,这样是为了实现C语法的需要,在case 语句块中没有break语句时,可以顺序执行后续的case语句块。

当switch的分支小于4的情况下,采用模拟if……else if 的方法,并没有发挥出switch的优势。当分支数大于3时,并且case的判定值存在明显线性关系组合时,switch的优化特性便可以凸显出来。

1.分支数大于3时,并且case的判定值存在明显线性关系组合时:
会为case语句制作一份case地址数组(或者称为“case地址表”),我一般叫它case表。在这里插入图片描述

此数组保存了每个case语句块的首地址,并且数组下标是以0为起始。在这里插入图片描述

而case中的最小值是1,与case地址表的起始下标是不对应的,所以需要edx-1调整,使其可以作为表格的下标进行寻址。

如果没有case对应的数值,编译器以switch的结束地址或者default语句块的首地址填充对应的表格
举个例子,也就是switch选项有 1,3,5,7,则case表(数组)里面第0,2,4,6项分别对应1,3,5,7,的地址,case表(数组)的1,3,5项全是switch的结束地址或者default语句块的首地址
这里也就是后面所说的 有序线性地址表重复保存switch的结束地址
case表项数:
case最大值-case最小值 ,中间空的直接用switch的结束地址或者default语句块的首地址去填充。

2.难以构成跳转表的switch
前提条件:索引表中保存了地址表中的下标值,索引表中最多可以存储256项,每一项的大小为1字节,这决定了case值不可以超过1字节的最大表示范围(0~255),因此索引表也只能存储256项索引编号

非线性的switch结构,可以采用制作索引表的方法来进行优化。索引表优化,需要两张表:一张为case语句块地址表(有多少个case,地址表就会有多少项),另一张为case语句块索引表(索引表保存了地址表的下标值,它的大小等于最大case值和最小case值的差)

与上面制作单一的case线性地址表相比,制作索引表的方式更加节省空间,但是由于在执行时需要用过索引表来查询地址表,会多出一次查询地址表的过程,因此效率会有所下降。
此方案所占用的内存空间如下:
(MAX-MIN)1字节=索引表大小
SUM
4字节=地址表大小
占用总字节数=((MAX-MIN)1字节)+(SUM4字节)

首先case值与索引表下标对齐操作:
case的最小值MIN对应是索引表(数组)的第0项,其它的(i)依次减去最小值对应索引表(数组)的第(i-MIN)项,然后找到这个索引表位置之后,根据地址表所填地址的数组所在的项数填入索引表中(数组项数依然从0开始算)。(即case值用来找索引表里面具体位置,索引表具体位置里面的具体内容得根据地址表来填入)

索引表如下:
在这里插入图片描述

因此地址表所对应的索引表的下标+MIN就是case语句的标号值。
找到所对应的地址索引后*4(地址占4字节)+基地址 就可以找到case的地址。

地址表如下:
在这里插入图片描述

在索引表中重复出现的值,可以断定其是switch的结束地址或者是default语句块的首地址(或者没有代码)。。

在case语句块没有任何代码的情况下,索引表中也会出现相同标号。由于case中没有任何代码,当执行到它时,则会顺序向下,直到发现下一个case语句不为空为止。这时所有没有代码的case属于一段多个case值共用的代码。索引表中这些case的对应位置处所保存的都是这段共用代码在地址表中的下标值,所以出现了索引表标号相同的情况。

猜你喜欢

转载自blog.csdn.net/CSNN2019/article/details/110246765