2014-01-12 17 views
-3

之間是否有區別,如果同時突破

if(x){ 

    //stuff 
} 

while(x){ 

    //stuff 
    break; 
} 

之間的差異?

其中一個更快?

+1

獲取有關C++的入門書! – Nawaz

+0

@Nawaz我想你無法在介紹性書籍 – Vider7CC

+2

中發現我懷疑有人生氣。如果你確實對此感興趣,那麼實際測量它並檢查你自己是否真的沒有想到這一點是令人驚訝的。或者閱讀更多關於C++的內容。 – BartoszKP

回答

4

讓我們找到它了:

void Test1() { 
    while (GetTickCount()) { 
     printf("Hello World Test1"); 
     break; 
    } 
} 

void Test2() { 
    if (GetTickCount()) { 
     printf("Hello World Test2"); 
    } 
} 

void main() { 
    Test1(); Test2(); 
} 

編譯使用VC 2013年11月CTP的釋放與全面優化:

CPU Disasm 
Address Hex dump   Command         Comments 
012A12A0 /$ FF15 00302A01 CALL DWORD PTR DS:[<&KERNEL32.GetTickCou ; [KERNEL32.GetTickCount 
012A12A6 |. 85C0   TEST EAX,EAX 
012A12A8 |. 74 0E   JZ SHORT 012A12B8 
012A12AA |. 68 8C312A01 PUSH OFFSET 012A318C      ; ASCII "Hello World Test1" 
012A12AF |. FF15 64302A01 CALL DWORD PTR DS:[<&MSVCR120.printf>] 
012A12B5 |. 83C4 04  ADD ESP,4 
012A12B8 |> FF15 00302A01 CALL DWORD PTR DS:[<&KERNEL32.GetTickCou ; [KERNEL32.GetTickCount 
012A12BE |. 85C0   TEST EAX,EAX 
012A12C0 |. 74 0E   JZ SHORT 012A12D0 
012A12C2 |. 68 A0312A01 PUSH OFFSET 012A31A0      ; ASCII "Hello World Test2" 
012A12C7 |. FF15 64302A01 CALL DWORD PTR DS:[<&MSVCR120.printf>] 
012A12CD |. 83C4 04  ADD ESP,4 
012A12D0 |> 33C0   XOR EAX,EAX 
012A12D2 \. C3   RETN 

正如你可以看到相同的代碼由VC編譯器生成。這雖然不是這種情況,如果禁止優化:

Test1的

CPU Disasm 
Address Hex dump   Command         Comments 
00F91630 /$ 55   PUSH EBP         ; Playground.Test1(void) 
00F91631 |. 8BEC   MOV EBP,ESP 
00F91633 |> FF15 0030F900 /CALL DWORD PTR DS:[<&KERNEL32.GetTickCo ; [KERNEL32.GetTickCount 
00F91639 |. 85C0   |TEST EAX,EAX 
00F9163B |. 74 12   |JZ SHORT 00F9164F 
00F9163D |. 68 9C31F900 |PUSH OFFSET 00F9319C     ; ASCII "Hello World Test1" 
00F91642 |. FF15 6430F900 |CALL DWORD PTR DS:[<&MSVCR120.printf>] 
00F91648 |. 83C4 04  |ADD ESP,4 
00F9164B |. EB 02   |JMP SHORT 00F9164F 
00F9164D |.^ EB E4   \JMP SHORT 00F91633 
00F9164F |> 5D   POP EBP 
00F91650 \. C3   RETN 

的Test2

CPU Disasm 
Address Hex dump   Command         Comments 
00F91660 /$ 55   PUSH EBP         ; Playground.Test2(void) 
00F91661 |. 8BEC   MOV EBP,ESP 
00F91663 |. FF15 0030F900 CALL DWORD PTR DS:[<&KERNEL32.GetTickCou ; [KERNEL32.GetTickCount 
00F91669 |. 85C0   TEST EAX,EAX 
00F9166B |. 74 0E   JZ SHORT 00F9167B 
00F9166D |. 68 B031F900 PUSH OFFSET 00F931B0      ; ASCII "Hello World Test2" 
00F91672 |. FF15 6430F900 CALL DWORD PTR DS:[<&MSVCR120.printf>] 
00F91678 |. 83C4 04  ADD ESP,4 
00F9167B |> 5D   POP EBP 
00F9167C \. C3   RETN 

正如你可以清楚地看到它們之間略有差別:

  • 如果條件得不到滿足,他們的行爲完全一樣的(從而以相同的速度執行)

  • 如果條件滿足,在Test1我們必須執行多一個跳躍(00F9164B - JMP SHORT 00F9164F

=>Test2從理論上講,如果代碼編譯時沒有進行優化,速度會更快,因爲編譯器會輸出一個真實的循環,用於Test1


這是不成熟的優化嗎? 絕對!

2

在彙編程序中輸出代碼並查看它是否與編譯器相同(更有可能的是,編譯器將對邏輯上相同的機器代碼進行優化)。幾乎總是編寫可讀和可維護的代碼比擔心諸如此類的細節更重要。隨着現代編譯器能夠優化這種簡單的情況,除了以最可讀的方式編寫代碼之外,沒有什麼理由做任何事情了,在這種情況下,我認爲將代碼編寫爲if語句表明您的意圖向您的其他讀者代碼遠遠好於while + break的組合。

8

邏輯上它們是相同的。編譯器可能會寫出相同的代碼。

您應該專注於代碼的清晰度,而不是考慮在昏迷的希望中編寫混淆代碼,以使代碼更快。

1
while(x){ 

    //stuff 
    break; 
} 

如果您只對給定條件執行一次操作,上面的代碼似乎不合理。這就是爲什麼如果在這種情況下聲明更可取!至於速度差異,我真的懷疑其中一個的重要優勢。在地點的使用while循環的if語句是可怕的:

if(condition) 
{ 
    // do stuff 
} 
else if(another_condition) 
{ 
    // do stuff 
} 
else 
{ 
    // do stuff 
} 

這裏是一個使用while循環等價的:

while(condition) 
{ 
    // do stuff 
    break; 
} 
while(!condition && another_condition) 
{ 
    // do stuff 
    break; 
} 
while(!condition && !another_condition) 
{ 
    // do stuff 
    break; 
} 

做你的團隊一個忙,讓你的代碼可讀性:-)

+0

但我的代碼將是唯一的! ;)開玩笑 – Vider7CC

+0

獨特並不總是一件好事:) – pcnThird

2

這是一樣的。雖然在理論上,while()增加了一個jmp比if if

+0

爲什麼這樣?這個額外的跳躍在哪裏? –

+0

@DavidHeffernan'break'後,如果編譯器沒有優化,它仍然需要跳轉到條件。雖然它將永遠不會被執行,因爲'break' –

+0

編譯器只會在它是垃圾時才寫出它。如果你關心性能,爲什麼你會使用不做優化的垃圾編譯器? –

1

他們有簡單的不同的目的。

if是一個選擇語句

while是循環語句。

而且他們應該相應地用於他們的目的。

+1

問題的上下文表明它在詢問性能方面的差異,而不是一般性問題。 – BartoszKP

1

如果在第一次迭代中斷開while循環,則while循環將充當if語句。

但是你不應該爲此目的使用while循環,因爲它的目的是循環。

-1

因此,以下可能會給出相同的結果,因爲for是被C預處理器修改爲一段時間。儘管......其他人對清晰度的評價

for(;x;){ 
    //stuff 
    break; 
} 
+0

如果你沒有回答這個問題,那麼請把它作爲評論。謝謝。 –