當我發現我只能在C++的switch
語句中使用數值時,我認爲它和一堆if-else
之間必然存在一些更深的差別。在Visual C++中如何進行開關編譯以及其優化和快速如何?
所以我問自己:
- (如何)不
switch
從if-elseif-elseif
在運行速度方面有所不同,編譯時間優化和一般彙編?我主要在這裏講MSVC。
當我發現我只能在C++的switch
語句中使用數值時,我認爲它和一堆if-else
之間必然存在一些更深的差別。在Visual C++中如何進行開關編譯以及其優化和快速如何?
所以我問自己:
switch
從if-elseif-elseif
在運行速度方面有所不同,編譯時間優化和一般彙編?我主要在這裏講MSVC。一個開關通常被編譯爲一個跳轉表(比較一個以找出要運行的代碼),或者如果這是不可能的,編譯器仍然可以對比較進行重新排序,以執行二分查找值之間(log N比較)。一個if-else鏈是一個線性搜索(儘管我猜想,如果所有相關的值都是編譯時積分常量,編譯器原則上可以執行類似的優化)。
開關語句通常是編譯器優化的常見來源。也就是說,它們的處理方式取決於您在編譯器上使用的優化設置。
編譯switch語句的最基本的(未優化的)方式是將其視爲一個if ... else if ...
語句的鏈。該編譯器優化開關的常用方法是將其轉換爲一個jump table可以看起來像:
if (condition1) goto label1;
if (condition2) goto label2;
if (condition3) goto label3;
else goto default;
label1:
<<<code from first `case statement`>>>
goto end;
label2:
<<<code from first `case statement`>>>
goto end;
label3:
<<<code from first `case statement`>>>
goto end;
default:
<<<code from `default` case>>>
goto end;
end:
一個原因這個方法更快是因爲條件語句中的代碼是小(所以有一個小的指令緩存如果條件被錯誤預測則罰款)。另外,「fall-through」情況變得更加微不足道(編譯器留下goto end
聲明)。
編譯器可以通過創建一個指針數組(通過標籤標記的位置)來進一步優化跳轉表,並使用您打開的值作爲該數組的索引。這將消除代碼中的幾乎所有條件(除了驗證您所接入的值是否與您的某個案例相匹配所需的內容)。
請注意:嵌套跳轉表很難生成,有些編譯器甚至拒絕創建一個。因此,如果最大限度優化的代碼對您很重要(我不是100%確定MSVC如何處理嵌套的switch
es,但編譯器手冊應告訴您),請避免在另一個switch
中嵌套switch
。
+1爲好的答案。我也將利用這個機會貶低if-then-elseif鏈。不止一個「其他」如果是DDD(設計缺陷障礙)的標誌。 – 2010-07-19 15:15:46
這是VisualC++的[真實世界C++開關實現](http://www.codeproject.com/Articles/100473/Something-You-May-Not-Know-About-the-Switch-Statem)。 – 2014-06-24 09:42:57
現在,如果這是優化,如果他們可以,這將是很好的。 – Lothar 2015-11-15 21:11:31