2009-06-12 29 views
45

在另外一個問題,我剛纔發現的這個小珍珠Ç智慧:「#define for if(false){} else for」的可能用途是什麼?

#define for if (false) {} else for 

造成MSVC地吐出了一個相當有效的語句「常量表達式」警告:

for (int i = 0; i <= 10; i++) {...} 

我瞭解爲什麼 MSVC抱怨,因爲它擴展爲:

if (false) {} else for (int i = 0; i <= 10; i++) {...} 

我只是不明白爲什麼開發人員會使用這個小片段。任何人有想法?

回答

92

這是對修復舊版本的Visual C++(v6.0及更早版本)中的錯誤。在過去,的Visual C++打破了有關內部for語句聲明的變量的作用域規則:

// This compiles in old versions of Visual C++, but it is in fact INVALID C++ 
for(int i = 0; ...) 
{ 
    ... 
} 

for(i = 0; ...) 
{ 

} 

換句話說,的Visual C++給i一個範圍,如果它被宣佈爲外循環,它可以讓你繼續使用它循環完成後。這導致了代碼,如上面的代碼片段。在更符合標準的編譯器中,i已不在第二個for循環的定義範圍內,因此編譯器發出關於i未定義的錯誤。

爲了解決這個問題,有些人使用這個宏(或非常相似,相當於宏):

#define for if(0) {} else for 

這改變了for循環到這一點:

if(0) 
{ 
} 
else 
    for(int i = 0; ...) 
    { 
     ... 
    } 

這使for環成這是一個額外的範圍,所以在for循環中聲明的任何變量都將超出範圍,而不管Visual C++的錯誤。這確保相同的代碼在Visual C++和符合標準的編譯器中都能夠正確編譯,並且不正確的代碼不能一致地編譯。

還要注意,如果宏被改爲定義爲這樣:

// DO NOT USE 
#define for if(1) for 

然後儘管這對一些簡單的代碼相同的效果,它會突然導致下面的代碼不正確地編譯:

if(foo) 
    for(...) 
    { 
     ... 
    } 
else 
    doSomething(); 

因爲如果展開宏,你將會得到:

if(foo) 
    if(1) 
     for(...) 
     { 
      ... 
     } 
    else 
     doSomething(); 

else現在與錯誤的if匹配!因此,巧妙使用if(0) {} else而不是if(1)可以避免這個問題。

作爲最後一點,#define for if(0) {} else for不會導致無限遞歸,因爲預處理器不會遞歸地替換您當前定義的宏。在這種情況下它只會做一個替換。

7

根據快速搜索它是一個MSVC中的錯誤被克服。

據我瞭解,

 
for(int i=0...){.....} 
//later at the same scope level in the same function 
for(int i=0...){...} 

會導致 '我' 的錯誤的重新定義。

如果for語句被封閉在一個if語句,編譯器的工作,因爲它應該讓沒有重新定義錯誤(顯然它解釋「如果」,但不是「對」的範圍水平)

+0

什麼是相關性?我不明白。此外,我不會說這是一個錯誤。這不是範圍工作的方式嗎? – 2009-06-12 04:30:09

+0

是的,這聽起來更真實。問:他們爲什麼會把if(false){}條件而不是簡單的if(1)。 – 2009-06-12 04:31:47

1

效果已經被描述。

它的原因是將C++代碼移植到MSVC。或者,如果你希望你的C++代碼平臺獨立,它也是非常有用的。例如,你在Linux/MacOSX上開發它,現在想在MSVC中編譯它。

它對C++本身也非常有用。例如:

for(std::set<Foo>::iterator i = myset.begin(); i != myset.end(); ++i) { 
    // ... 
} 

for(int i = 0; i < N; ++i) { 
    // ... 
} 

我看到MSVC的代碼,圍繞這個工作做兩種:

for(std::set<Foo>::iterator i1 = myset.begin(); i1 != myset.end(); ++i1) { 
    // ... 
} 

for(int i2 = 0; i2 < N; ++i2) { 
    // ... 
} 

或者:

{for(std::set<Foo>::iterator i = myset.begin(); i != myset.end(); ++i) { 
    // ... 
}} 

{for(int i = 0; i < N; ++i) { 
    // ... 
}} 

在這兩種情況下(IMO)不是很好。而這個#define是一個小小的破解,使MSVC的行爲更加標準。

2

由於msvc編譯器錯誤地處理默認情況下在for語句中聲明的變量範圍。爲了避免這種行爲,你必須關閉微軟的擴展,然後使ms頭文件不能編譯。

我使用(是的,我仍然使用vs6)一個不會導致vs6中的警告,儘管英特爾編譯器仍然發現它。

#define for switch(0) case 0: default: for 

我不記得我是從得到它,但我懷疑,我發明了它;-)

我知道其他的答案已經說這個最,但彈出說要確保你回答了這個問題。