2013-02-02 39 views
3

我在看代碼,別人寫了優化代碼,它有很多調試節,類型C++企圖通過更換測試

if(0) { code } 

if(1) { code }

if(false) { code }

甚至有

#if(0) 
#endif 

(它沒有轉灰 - 但我認爲它應該)

我想知道,如果我用幾個#if 0(或#ifdef _DEBUG)替換這些,可以優化代碼嗎? - 或者 - 它不會有什麼區別?

我認爲這可能會有所幫助,因爲我已經看到這些部分中的代碼被灰顯 - 我認爲這段代碼已從發佈可執行文件中刪除...因此使其更快。真的嗎 ?

,我正在盤算的代碼是內部函數可以被稱爲很多次......

編輯:我指的是代碼正在運行數百萬次。我知道if(0)的內容將被忽略...

我也意識到通過將測試從0切換到1,能夠輕鬆調試問題的好處...

我的問題是,我添加了數百萬次的測試,如果(0)不會增加開銷的事實......我想弄清楚什麼是可以使這段代碼花費更少的時間。

回答

2

如果置於這些IF內部的表達式爲爲常量,並且在編譯時可確定,那麼您可能幾乎可以確定編譯器已將它們從代碼中移除。當然,如果你在調試模式下編譯,和/或如果你的優化級別設置爲零,那麼編譯器可能會跳過這個並且離開那些測試 - 但是用簡單的零/一個/真/假值這是不太可能的。

對於編譯時常量分支,您可能確定編譯器刪除了死亡分支。

它能夠去除即使是複雜的,看情況,如:

const int x = 5; 

if(3 * x * x < 10) // ~ 75 < 10 
{ 
    doBlah(); // skipped 
} 

然而,如果沒有那「常量」在X標記,表達式的值可以在編譯時無法確定,也可能「泄漏「到實際的最終產品中。

此外,表達在下面的代碼的值不是necesarily編譯時間常數:

const int x = aFunction(); 

if(3 * x * x < 10) // ~ 75 < 10 
{ 
    doBlah(); // skipped 
} 

X是一個常數,但它與從函數值進行初始化。 X在編譯時很可能無法確定。在運行時,函數可以返回任何值*),因此編譯器必須假定X是未知的。

因此,如果有可能,然後使用預處理器。在微不足道的情況下,因爲編譯器已經知道這一點。但情況並不總是微不足道的,你會經常注意到變化。當優化器未能推導出這些值時,即使該代碼已經死亡,也會留下代碼。另一方面,預處理器保證在被禁用的部分被編譯和優化之前刪除。另外,使用預處理器至少會加快編譯速度:編譯器/優化器將不必跟蹤常量/計算/校驗分支等。

*)可以編寫一個返回值的方法/函數是在編譯和優化階段確定:如果函數是簡單的,如果它被內聯,其結果值可能與一些分支機構一起優化了..但是,即使你能有所依靠去除如果-0的條款,你不能儘可能多地依賴內聯。

+0

譯文:如果我做這個改變,我將不會獲益? – Thalia

+0

編譯錯誤! const' –

+0

後的變量名或類型如果這些是if(0)if(false) - 則不是。也許在編譯時有一點加速,但不是在運行時。如果你的編譯器非常糟糕,或者你把所有的優化結果都拋棄了,你可能會在運行時加速。在所有其他情況下,如果(0)確實會在運行時存在。 – quetzalcoatl

1

這是真的(取決於您的構建設置和預處理器)。

將調試代碼放在#ifdef _DEBUG(或類似的地方)是一種標準的方法,可以使這些代碼完全脫離您的發佈版本。通常情況下,調試版本#define就是它,而發佈版本則不是。

通常,雖然,編譯器應該還,刪除代碼,比如if (0)如果給予適當的優化參數,但這就對編譯器的額外的工作,並在編程器(現在你必須去改變他們! )。我一定會把它留給預處理器。

2

如果在if (0)塊內有代碼,編譯器生成的代碼將與在任何合理的編譯器中不存在的代碼塊相同。代碼仍然會檢查編譯時錯誤。 (假設你內部沒有任何跳轉標籤或者其他奇怪的東西)

如果代碼在if (1)塊內,編譯器生成的代碼將與代碼剛好在花括號內。將代碼塊作爲自己的作用域是一種常用的方法,以便在需要時局部變量被破壞。

如果ifdef出來的代碼,那麼編譯器完全忽略它。代碼可能完全是無意義的,包含語法錯誤,或者其他什麼,編譯器不會在意。

1

你是正確的。如果使用#define DEBUG 0進行編譯,那麼在編譯時您將實際上刪除所有#if DEBUG塊。因此,代碼會少得多,而且運行速度會更快。

只要確保你在發佈時作出#define DEBUG 0後釋放你的代碼。

良好的優化編譯器(GCC,MSVC)將從代碼完全...翻譯成機器代碼不會爲這些條件下測試除去if(0)if(1) ...

2

通常,#if 0用於去除碼同時仍然保持它的周圍 - 比如可以輕鬆地比較選擇,我有時會做:

#if 1 
    some sort of code 
#else 
    some other code 
#endif 

這樣的話,我可以在兩個選擇之間快速切換。

在這種情況下,預處理器只會在代碼中留下兩個選項之一。

if(0)if(1)的結構是相似的 - 編譯器將幾乎刪除if,並且在0的情況下也刪除if語句的其餘部分。

我覺得在「完成」的代碼中留下這種東西是相當sl but的,但它對調試/開發非常有用。

說,例如,你正在嘗試一種新的方法做的事情是要快得多:

if (1) 
{ 
    fast_function(); 
} 
else 
{ 
    slower_function(); 
} 

現在,在你的測試用例之一,結果顯示錯誤。所以你想快速回到slower_funcion,看看結果是否相同。如果它是相同的,那麼你必須看看自上次通過以來還有哪些變化。如果對於slow_function沒有問題,你可以回頭看看爲什麼在這種情況下fast_function()不能正常工作。

+0

如果你使用一個體面的版本控制系統,你可以保留不同的分支機智/沒有周圍的變體。 – vonbrand

+0

當然,但如果您在同一個文件中有其他更改,一段時間後可能會變得非常混亂。如果你是唯一一個處理代碼的人,那很好,但是當其他人有很多人時,通常很難跟上其他人的變化,而不必去嘗試挖掘你的源代碼的五個舊版本你試圖做得更好,因爲發生了其他一些變化,所以不會編譯。我絕不會暗示這些東西會永久留在代碼中 - 只是在確保新代碼像舊代碼一樣工作的時候。 –

+0

well ..簡單地說,'if(0){...}'比#define OOPS ... #ifndef OOPS ..#endif' :)))要快得多 – quetzalcoatl