2014-12-03 21 views
2

在下面的非常簡單的C程序中,預期的編譯器錯誤是什麼? GCC是給我1,而MSVC 2013年給了我2對已設置爲defined()的結果的宏有什麼期望值?

#define foo 
#define bar (defined(foo)) 

#if bar 
#error 1 
#else 
#error 2 
#endif 

我的問題是希望同樣簡單:

  1. 什麼是C時的參數說一下的價值定義()?我似乎無法找到 找到任何有關將其值設置爲另一個 宏的內容。
  2. 實際的代碼不是我可以控制的,並且「#if bar」會在整個地方使用。什麼是最簡單的方式來更改#define,以便在MSVC中#if欄將以「預期」的方式工作?我能想到的唯一辦法就是將其展開:

#ifdef foo 
#define bar 1 
#else 
#define bar 2 
#endif 
+0

我自己測試過,這是bizzare。我無法想象MSVC認爲它在這裏做什麼。 – 2014-12-03 18:20:19

回答

2

的C時的參數表示:

§6.10.1/ 1所述的表達...可包含如果標識符是當前定義的形式defined identifierdefined(identifier)其評估爲1的一元運算符的表達式作爲宏名稱(即,如果它是預定義的,或者如果它已經是#define預處理指令的主題而沒有介入具有相同主題標識符的介入#undef指令),則0如果不是。在預處理標記,這將成爲 的控制常量表達式列表

§6.10.1/ 4宏調用被替換(除了那些宏名稱由defined元運算符改性 ),就如同在普通文本。 如果令牌defined是 ,因爲這替換處理或使用defined一元運算符 的結果不匹配的宏替換之前的兩個指定的形式之一生成,行爲是 未定義。在所有由於宏擴展而導致的替換以及運算符已被執行後,將所有其餘標識符(包括與關鍵字詞法上相同的詞彙 )替換爲pp-0,然後將每個預處理 令牌轉換爲令牌。

(重點煤礦) 然而,如何宏替換是非常複雜的,而且我認爲MSVC被定義爲foodefined(bar)是不確定的行爲,wheras GCC正確定義foo1。由於MSVC然後在未定義的行爲,它做奇怪的事情。

正如你所說的,最簡單的解決方法是

#ifdef foo 
#define bar 1 
#else 
#define bar 2 
#endif 
+1

我不認爲MSVC有什麼問題。在這種情況下,*由於替換過程*而生成令牌'defined'。規範清楚地表明它是UB,因此實施供應商可以自由選擇任何行動方案。編譯器甚至可能包含條件片段的兩個分支,這將是一個合法的樂趣。 – ach 2014-12-03 19:37:21

+0

@AndreyChernyakhovskiy:我也總結了UB,但在重讀時,我的推理是錯誤的;你是對的。 – 2014-12-03 20:09:09

+0

我停止閱讀規範一段太快。我認爲這是UB,但想確認。謝謝您的幫助! – 2014-12-04 00:03:04

0

相信定義爲名稱/宏的定義,那就是部分名稱/宏噓寒問暖編譯器將看到的一切,因爲程序文本,而不是宏觀文本。在程序文本

int defined(char s); // prototype of a function named "defined" 

#define foo 
#define bar defined(foo) 

「酒吧」的任何地方現在將調用定義()不帶參數(如「foo」被定義爲空)取代。

+0

'defined'是一個神奇的預處理器函數>任何同名的C/C++函數都可能被忽略。 (有這樣的事情可能是未定義的行爲,我必須檢查) – 2014-12-03 20:12:15

+0

@MooingDuck,你爲什麼這麼認爲? 'defined'只被定義爲在'#if'和'#elif'條件表達式中有特殊含義。將'defined'作爲標識符否則是完全合法的。 – ach 2014-12-03 20:32:51

+0

我確定'defined'不是一個關鍵字,所以是,它只是被定義爲在'if'和'elif'中有特殊含義,在這種情況下,任何C/C++函數都被忽略。 (我真的想知道如果編譯器有'#define defined(x)1')什麼編譯器會做什麼 – 2014-12-03 20:42:57

相關問題