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的對應位置處所保存的都是這段共用代碼在地址表中的下標值,所以出現了索引表標號相同的情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章