欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++?反匯編之關(guān)于Switch語句的優(yōu)化措施

 更新時間:2022年01月28日 15:20:39   作者:lyshark  
這篇文章主要介紹了C++?反匯編之關(guān)于Switch語句的優(yōu)化措施,利用三種優(yōu)化來降低樹高度,誰的效率高就優(yōu)先使用誰,三種優(yōu)化都無法匹配才會使用判定樹,具體內(nèi)容詳情跟隨小編一起看看吧

流程控制語句是C語言中最基本的判斷語句,通常我們可以使用IF來構(gòu)建多分支結(jié)構(gòu),但同樣可以使用Switch語句構(gòu)建,Switch語句針對多分支的優(yōu)化措施有4種形式,分別是,IF-ELSE優(yōu)化,有序線性優(yōu)化,非線性索引優(yōu)化,平衡判定樹優(yōu)化。

與IF語句結(jié)構(gòu)不同,IF語句會在條件跳轉(zhuǎn)后緊跟語句塊,而SWITCH結(jié)構(gòu)則將所有條件跳轉(zhuǎn)都放置在一起,判斷時需要重點(diǎn)觀察每個條件跳轉(zhuǎn)指令后面是否跟有語句塊,以辨別SWITCH分支結(jié)構(gòu)。

在switch分支數(shù)小于4的情況下,編譯器將采用模擬IF-ELSE分支的方式構(gòu)建SWITCH結(jié)構(gòu),這樣則無法發(fā)揮出SWITCH語句的優(yōu)勢,當(dāng)分支數(shù)大于3并且case的判斷值存在明顯線性關(guān)系時,Switch語句的優(yōu)化特性才可以凸顯出來。

有序線性優(yōu)化: 該優(yōu)化方式將每個case語句塊的地址預(yù)先保存在數(shù)組中,并依據(jù)此數(shù)組查詢case語句塊對應(yīng)的首地址。

首先代碼生成時會為case語句制作一個case地址表數(shù)組,數(shù)組中保存每個ease語句塊的首地址,并且下標(biāo)以0開頭,在進(jìn)入switch后先進(jìn)行一次比較,檢查輸入的數(shù)值是否大于case值的最大值,

為了達(dá)到線性有序,對于沒有case對應(yīng)的數(shù)值,編譯器以switch的結(jié)束地址或者default語句塊的首地址填充對應(yīng)的表格項(xiàng)。

case線性地址表是一個有序表。

當(dāng)switch為一個有序線性組合時,會對其case語句塊制作地址表,以減少比較跳轉(zhuǎn)次數(shù)。

在編寫代碼時,我們無需自己排列case序列,編譯器編譯時會自動進(jìn)行排序優(yōu)化,先來編寫一個簡單的代碼:

int main(int argc, char *argv[])
{
	int index = 0;

	scanf("%d", &index);
	switch (index)
	{
	case 1:
		printf("index 1"); break;
	case 2:
		printf("index 2"); break;
	case 3:
		printf("index 3"); break;
	case 6:
		printf("index 6"); break;
	case 7:
		printf("index 7"); break;
	default:
		printf("default"); break;
	}
	return 0;
}

代碼經(jīng)過反匯編后,我們可以注意到,首先用戶通過scanf輸入所需要執(zhí)行的分支,因?yàn)榉种дZ句下標(biāo)從0開始,所以需要dec eax減去1,在進(jìn)入switch語句之前,判斷輸入的下標(biāo)是否高于6,如果高于則直接跳出switch,否則執(zhí)行ds:[eax*4+0x401348]尋址。

004012B4 | FF15 B8304000            | call dword ptr ds:[<&scanf>]              |
004012BA | 8B45 FC                  | mov eax,dword ptr ss:[ebp-4]              |
004012BD | 83C4 08                  | add esp,8                                 |
004012C0 | 48                       | dec eax                                   | Switch語句獲取比例因子,需要減1
004012C1 | 83F8 06                  | cmp eax,6                                 | 首先對比輸入數(shù)據(jù)是否大于6
004012C4 | 77 6B                    | ja consoleapplication.401331              | 大于則說明Switch分支無對應(yīng)結(jié)構(gòu) (則直接跳轉(zhuǎn)到結(jié)束)
004012C6 | FF2485 48134000          | jmp dword ptr ds:[eax*4+0x401348]         | 跳轉(zhuǎn)到指定代碼段

地址0x401348對應(yīng)的就是每一個分支的首地址,跳轉(zhuǎn)后即可看到分支。

非線性索引優(yōu)化: 如果兩個case值間隔較大,仍然使用switch的結(jié)尾地址或default地址代替地址表中缺少的case地址,這樣則會造成極大的空間浪費(fèi)。

非線性的switch結(jié)構(gòu),可采用制作索引表的方式進(jìn)行優(yōu)化,索引表有兩張,1.case語句塊地址表,2.case語句塊索引表。

地址表中每一項(xiàng)保存一個case語句塊首地址,有幾個case語句塊或default語句塊,就保存幾項(xiàng),結(jié)束地址在地址表中指揮保存一份。

索引表中保存了地址表中的下標(biāo)值,索引表最多可容納256項(xiàng),每項(xiàng)1字節(jié),所以case值不可超過1字節(jié),索引表也只能存儲256項(xiàng)索引編號。

在執(zhí)行時需要通過索引表來查詢地址表,會多出一次查表的過程,因此效率上會有所下降。

004012B4 | FF15 B8304000            | call dword ptr ds:[<&scanf>]              |
004012BA | 8B45 FC                  | mov eax,dword ptr ss:[ebp-4]              |
004012BD | 83C4 08                  | add esp,8                                 |
004012C0 | 48                       | dec eax                                   | Switch語句獲取比例因子,需要減1
004012C1 | 3D FE000000              | cmp eax,FE                                | 首先對比輸入數(shù)據(jù)是否大于254
004012C6 | 0F87 80000000            | ja consoleapplication.40134C              | 跳轉(zhuǎn)到指定代碼段
004012CC | 0FB680 70134000          | movzx eax,byte ptr ds:[eax+0x401370]      | 從索引表找地址表下標(biāo)
004012D3 | FF2485 54134000          | jmp dword ptr ds:[eax*4+0x401354]         | 比例因子尋找函數(shù)地址

首先movzx eax, byte ptr ds:[eax+0x401370]從索引表中找到地址表下標(biāo)。

然后通過索引表找到索引值,并帶入jmp dword ptr ds:[eax*4+0x401354]找到地址表中的指定地址,地址表中每一個地址就代表一個分支結(jié)構(gòu)里的函數(shù)。

這樣的優(yōu)勢就是可以節(jié)約空間,每一個所以表字段只占1字節(jié),如果兩個case差距較大同樣會指向同一個地址表中的地址,地址表相對來說會變得簡單,但這種查詢方式會產(chǎn)生兩次間接內(nèi)存訪問,在效率上遠(yuǎn)遠(yuǎn)低于線性表方式。

平衡判定樹優(yōu)化: 當(dāng)最大case值與最小case值之差大于255時,則會采用判定樹優(yōu)化,將每個case值作為一個節(jié)點(diǎn),從節(jié)點(diǎn)中找出中間值作為根節(jié)點(diǎn),以此形成一顆平衡二叉樹,以每個節(jié)點(diǎn)為判定值,大于和小于關(guān)系分別對應(yīng)左子樹和右子樹,從而提高查詢效率。

如果打開編譯器體積優(yōu)先,編譯器盡量會以二叉判定樹的方式來降低程序占用體積,如果無法使用以上優(yōu)化方式,則需要將switch做成樹。

int main(int argc, char *argv[])
{
	int index = 0;

	scanf("%d", &index);
	switch (index)
	{
	case 2:
		printf("index 2"); break;
	case 3:
		printf("index 3"); break;
	case 8:
		printf("index 8"); break;
	case 10:
		printf("index 10"); break;
	case 35:
		printf("index 35"); break;
	case 37:
		printf("index 37"); break;
	case 666:
		printf("index 666"); break;
	}
	return 0;
}

判定樹反匯編形式。

004012C0 | 83F8 0A                  | cmp eax,A                                 | A:'\n'
004012C3 | 7F 63                    | jg consoleapplication.401328              |
004012C5 | 74 4D                    | je consoleapplication.401314              |
004012C7 | 83E8 02                  | sub eax,2                                 |
004012CA | 74 34                    | je consoleapplication.401300              |
004012CC | 48                       | dec eax                                   |
004012CD | 74 1D                    | je consoleapplication.4012EC              |
004012CF | 83E8 05                  | sub eax,5                                 |
004012D2 | 0F85 97000000            | jne consoleapplication.40136F             |
004012D8 | 68 A0314000              | push consoleapplication.4031A0            | main.cpp:16, 4031A0:"index 8"
004012DD | FF15 B4304000            | call dword ptr ds:[<&printf>]             | main.cpp:20
004012E3 | 83C4 04                  | add esp,4                                 |

判定樹,通過增加多條分支結(jié)構(gòu),從中位數(shù)開始判斷,大于或小于分別走不同的分支,直到遇到函數(shù)地址位置。

為了降低數(shù)的高度,在優(yōu)化過程中,會檢查代碼是否滿足if-else優(yōu)化,有序線性優(yōu)化,非線性索引優(yōu)化,利用三種優(yōu)化來降低樹高度,誰的效率高就優(yōu)先使用誰,三種優(yōu)化都無法匹配才會使用判定樹。

到此這篇關(guān)于C++ 反匯編之關(guān)于Switch語句的優(yōu)化措施的文章就介紹到這了,更多相關(guān)C++ 反匯編Switch語句優(yōu)化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解C++設(shè)計(jì)模式編程中責(zé)任鏈模式的應(yīng)用

    詳解C++設(shè)計(jì)模式編程中責(zé)任鏈模式的應(yīng)用

    這篇文章主要介紹了C++設(shè)計(jì)模式編程中責(zé)任鏈模式的應(yīng)用,責(zé)任鏈模式使多個對象都有機(jī)會處理請求,從而避免請求的發(fā)送者和接收者之間的耦合關(guān)系,需要的朋友可以參考下
    2016-03-03
  • C++ 在 Unreal 中為游戲增加實(shí)時音視頻互動的教程詳解

    C++ 在 Unreal 中為游戲增加實(shí)時音視頻互動的教程詳解

    這篇文章主要介紹了C++ 在 Unreal 中為游戲增加實(shí)時音視頻互動的教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • C++?Boost?Conversion超詳細(xì)講解

    C++?Boost?Conversion超詳細(xì)講解

    Boost是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱。Boost庫是一個可移植、提供源代碼的C++庫,作為標(biāo)準(zhǔn)庫的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開發(fā)引擎之一,是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱
    2022-11-11
  • vs2019 Com組件初探之簡單的COM編寫及實(shí)現(xiàn)跨語言調(diào)用的方法

    vs2019 Com組件初探之簡單的COM編寫及實(shí)現(xiàn)跨語言調(diào)用的方法

    這篇文章主要介紹了vs2019 Com組件初探之簡單的COM編寫及實(shí)現(xiàn)跨語言調(diào)用的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • C語言多維數(shù)組數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)詳解

    C語言多維數(shù)組數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)詳解

    對于數(shù)組想必大家都不陌生首先得要知道的是對于數(shù)組元素在內(nèi)存存儲是連續(xù)性的,下面這篇文章主要給大家介紹了關(guān)于C語言多維數(shù)組數(shù)據(jù)結(jié)構(gòu)的相關(guān)資料,需要的朋友可以參考下
    2021-12-12
  • C指針原理教程之Ncurses介紹

    C指針原理教程之Ncurses介紹

    Ncurses 提供字符終端處理庫,包括面板和菜單。為了能夠使用ncurses庫,您必須在您的源程序中將curses.h包括(include)進(jìn)來,而且在編譯的需要與它連接起來. 在gcc中您可以使用參數(shù)-lcurses進(jìn)行編譯.
    2019-02-02
  • C語言超詳細(xì)講解函數(shù)指針的運(yùn)用

    C語言超詳細(xì)講解函數(shù)指針的運(yùn)用

    函數(shù)指針是一個指針變量,它可以存儲函數(shù)的地址,然后使用函數(shù)指針,下面這篇文章主要給大家介紹了關(guān)于C語言進(jìn)階教程之函數(shù)指針的相關(guān)資料,需要的朋友可以參考下
    2022-06-06
  • [c++]變量聲明與定義的規(guī)則詳解

    [c++]變量聲明與定義的規(guī)則詳解

    這篇文章主要介紹了[c++]變量聲明與定義的規(guī)則詳解,對于學(xué)習(xí)c++的朋友來說這是一個很細(xì)膩的文章,代碼完整,需要的朋友可以參考下
    2021-04-04
  • C++ 設(shè)置控制臺(命令行)窗口 光標(biāo)位置,及前背景顏色

    C++ 設(shè)置控制臺(命令行)窗口 光標(biāo)位置,及前背景顏色

    這篇文章主要介紹了C++ 設(shè)置控制臺(命令行)窗口 光標(biāo)位置,及前背景顏色,需要的朋友可以參考下
    2019-04-04
  • QT生成隨機(jī)驗(yàn)證碼的方法

    QT生成隨機(jī)驗(yàn)證碼的方法

    這篇文章主要為大家詳細(xì)介紹了QT生成隨機(jī)驗(yàn)證碼的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06

最新評論