2009-03-01 133 views
3

我有這樣的代碼,我發現它有點難以閱讀:C/C++編譯器是否會優化if語句?

// code1 
if((expensiveOperation1() && otherOperation() && foo()) 
    || (expensiveOperation2() && bar() && baz()) { 
    // do something 
} 

我只是將其改變爲如下,以使其更易於閱讀:

// code2 
const bool expr1 = expensiveOperation1() && otherOperation() && foo(); 
const bool expr2 = expensiveOperation2() && bar() && baz(); 
if(expr1 || expr2){ 
    // one of the conditions met 
} 

但現在我應該關心效率?

我的意思是,在code1中,如果第一個連接子句得到滿足,那麼它甚至不會去查看第二個連接子句,因爲已經清楚該語句是正確的。

但在我更可讀的例子中,必須計算cond1cond2。或者如果expr2在其他地方沒有使用,編譯器是否足夠聰明,可以將code2更改爲code1

+0

我使用的gcc /克++(G ++ V3.4,要精確。)。 – Frank 2009-03-01 21:27:16

回答

24

我會說它不應該,因爲如果任何功能都有副作用,它們在邏輯上不等效。

下面就相當於然而,它就會有優勢可讓您爲描述性的名稱,以測試功能,使得代碼更自我記錄:

// code3 
inline bool combinedOp1() 
{ 
    return expensiveOperation1() && otherOperation() && foo(); 
} 

inline bool combinedOp2() 
{ 
    return expensiveOperation2() && bar() && baz(); 
} 

然後調用它,如下所示:

if (combinedOp1() || combinedOp2()) 
{ 
    // do something 
} 
19

也許,但爲什麼不只是讓你的第二個檢查合併第一個?

// code3 
bool expr = expensiveOperation1() && otherOperation() && foo(); 
expr = expr || (expensiveOperation2() && bar() && baz()); 
if(expr){ 
    // one of the conditions met 
} 

更重要的是,扭轉乾坤,那麼最便宜的檢查首先發生在每個列表,以懶惰評估的優勢,完全跳過了昂貴的操作。

+0

不錯 - 這些簡單的事情之一,可能在一百萬年後我不會想到。 – 2009-03-01 21:03:22

+0

尼斯,除了expr是聲明爲const所以第二行不會編譯:-)我猜你的意思是「常量布爾表達式1 = ...;常量布爾表達式2 =表達式1 ||(......)」 – SCFrench 2009-03-01 21:16:24

+0

切/粘貼錯誤。我可能不會讓它成爲const並重用它。 – tvanfosson 2009-03-01 21:27:08

4

好,一般編譯器不會重新排序& &的和||'上關的機會,條件有副作用秒。一些非常聰明的編譯器可能能夠靜態地驗證它們的獨立性,但這很少見。

如果可能,請重新排列廉價操作的條件,以便它可以將昂貴的操作短路。

1

這個問題的答案當然取決於編譯器。確定的方法是查看編譯器爲此函數生成的程序集。大多數(所有?)編譯器都有辦法做到這一點,例如gcc-S選項。如果出於某些奇怪的原因,你的大多數調試器都不能向你展示函數的反彙編,或者有其他工具可以完成此工作。

0

很好的答案。

我只會補充一點,我不喜歡編譯器在優化中如此激進以至於重新排序我的代碼。

我只是想要一個編譯器來做它所說的。

如果它能勝過我,它也可以超越自我。

2

這裏的頂部答案回答「不應該」和「也許」的問題!這不是一個明確的答案!

如果你想知道,如果你的編譯器優化的代碼,這麼一點點,用「顯示組件輸出」標誌編譯代碼。在GCC上,該標誌是「-S」。然後看看輸出組件,它會顯示你完全100%正在編譯或不是。

然後你就可以比較來自「therefromhere」剪斷的代碼片段你的第一個代碼,並迅速嘗試衆多的代碼修改,直到你找到一個編譯器優化最佳(即最小週期)。

這聽起來很複雜和可怕看ASM輸出,但在現實中,它僅需要5分鐘左右的事情。我在這裏做了一個例子:What is the fastest way to swap values in C?

0

如果知道cond2(expensiveOperation2(),bar()和baz())中的函數是純的(即沒有副作用),編譯器可以進行優化。如果它們是純的,確保編譯器知道它的最簡單方法是使它們成爲內聯函數。

這是可能編譯器可以告訴,即使你不這樣做,但由於其expensiveOperation2不太可能()可能做了很多的工作。如果這些函數是純的,你應該重新排序它們,以便bar()和baz()在expensiveOperation2()之前運行(並且在cond1中的排序相同)。