2013-04-10 144 views
4

爲什麼下面的代碼會被編譯?#ifdef指令末尾的額外令牌

#ifdef C++11 
// ... 
#endif 

int main() {} 

GCC 4.8.0給了我以下警告:

額外的令牌在#ifdef指令

末根據標準,宏的名稱只能包含字母,數字和下劃線字符。

也許是因爲這個?

ISO/IEC 14882:2011

16.1條件包含[cpp.cond]

6每個指令的條件是爲了檢查。如果它的計算結果爲 false(零),則它所控制的組被跳過:指令 僅通過確定指令的名稱進行處理,以 的順序跟蹤嵌套條件的級別;其餘 指令的預處理令牌將被忽略,其他 預處理令牌也會被忽略。只處理控制 條件評估爲真(非零)的第一組。如果 條件中沒有一個條件的計算結果爲true,並且存在#else指令,則處理由#else控制的組 ;缺少#else指令, 直到#endif跳過所有組.151

我無法正確理解此引號。

+0

我相信預處理器標識符遵循與變量標識符相同的規則,儘管大寫是首選。 「C++ 11」不起作用。這個SO問題應該可以幫助你:http://stackoverflow.com/questions/10717502/is-there-a-preprocessor-directive-for-detecting-c11x-support – 2013-04-10 20:01:15

+0

@Eric Jablow我知道__cplusplus宏,我想知道爲什麼這個代碼編譯在gcc 4.8.0,clang 3.2,icc 13.0.1和MSVC-11 – FrozenHeart 2013-04-10 20:26:47

+1

對不起。我應該讀得更好。也許GCC太寬容了。 – 2013-04-10 20:40:59

回答

1

#ifdef定義如下(取自§16.1)

  # ifdef       標識符新行

隨着正則表達式狀符號,標識符是:[a-zA-Z_][a-zA-Z_0-9]* (*)

問題是:您聲明的宏不是C++11。它實際上是C(見this live example)。預處理器忽略了++11部分。標識符後面的唯一允許的字符(即C)是一個新行,但正如hvd的答案中所述,來自§1.4的語法錯誤只會強制執行診斷消息,此處爲警告;我所看到的這個而不是一個錯誤的唯一原因是與舊代碼兼容,在這些舊代碼中可能會使用這些名稱。

另外:該報價解釋了#ifdef/#elif/#else/#endif如何一起工作,而不是指定條件的方式。

我沒有該標準的副本。這個答案我使用草稿n3485

(*)可能在標識符中有實現定義的字符,但這不會影響您的問題。請注意,變量,類名稱,宏,...都遵循相同的標識符規則。

+0

「我認爲這不符合標準」你確定嗎? gcc 4.8.0,clang 3.2,icc 13.0.1和MSVC-11編譯此代碼 – FrozenHeart 2013-04-10 20:48:36

+0

是的,但這並不意味着這是標準的。海灣合作委員會,鏗鏘不是標準的,他們試圖*遵循它。如果他們符合標準(在這一點上),他們會輸出一個錯誤,而不是一個警告(除非我錯過了某些東西)。 – Synxis 2013-04-10 20:49:33

+0

你是什麼意思「但是,這不是原因」?我認爲這個標準的引用允許在宏名稱中使用+,所以C++ 11可以是有效的宏名稱 – FrozenHeart 2013-04-10 20:51:00

3

就C++一致而言,#ifdef C++11是一個語法錯誤。沒有規則說編譯器必須拒絕帶有語法錯誤的程序。

1.4實施遵守[intro.compliance]

該組診斷的規則由除了含有顯式表示法這些規則在本國際標準的所有語法和語義規則,「沒有診斷是必需的」或這被描述爲導致「未定義的行爲」。

[...]

如果程序包含違反任何診斷的規則或本標準中所描述的建造物的出現爲「有條件支持」時,實現不支持該構造,一個合格執行應至少發出一條診斷消息。

警告是診斷消息。編譯器完全有權繼續成功編譯該程序,只要它們確保它們向您顯示一條診斷消息即可。由於編譯器歷來接受這樣的指令,並且接受這樣的指令不與標準的要求相沖突,他們繼續這樣做。

至少就GCC而言,您可以要求使用-pedantic-errors選項使所有標準要求的診斷成爲硬性錯誤。

$ printf "#ifdef C++11\n#endif\n" | gcc -std=c++11 -pedantic-errors -E -x c++ - 
# 1 "<stdin>" 
# 1 "<command-line>" 
# 1 "<stdin>" 
<stdin>:1:9: error: extra tokens at end of #ifdef directive