2011-02-27 94 views
33

考慮以下代碼:MSVC不展開__VA_ARGS__正確

#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__ 
#define G(...) F(__VA_ARGS__) 
F(1, 2, 3) 
G(1, 2, 3) 

預期的輸出是X = 1 and VA_ARGS = 2, 3兩個宏,這就是我與海灣合作委員會獲得,但是,MSVC擴展了這個爲:

X = 1 and VA_ARGS = 2, 3 
X = 1, 2, 3 and VA_ARGS = 

也就是說,__VA_ARGS__被擴展爲單個參數,而不是分解爲多個參數。

任何方法?

+6

我的第一個想法是獲得更好的編譯器。如果這是您在MSVC遇到的第一個也是最嚴重的錯誤,那麼您會遇到大量令人不快的意外... – 2011-02-27 17:10:55

+1

@R:沒有選項:P – uj2 2011-02-27 17:16:50

回答

34

MSVC的預處理器似乎與標準 規範有很大區別。
也許以下解決方法將幫助:

#define EXPAND(x) x 
#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__ 
#define G(...) EXPAND(F(__VA_ARGS__)) 
+0

'__VA_ARGS__'還不是標準C++的一部分。標準草案是否確實規定了這種情況下的行爲? – bk1e 2011-02-27 17:42:19

+1

@ bk1e:對不起,因爲我沒有這個能力,所以我不能在這裏詳細解釋即將到來的 C++標準中的預處理過程,但它不可能與C99的 差別很大。 – 2011-02-27 19:45:00

+1

有人可以解釋一下嗎? 「and VA_ARGS = __VA_ARGS__」是一段有效的C代碼,還是隻是一個可讀的文本,在這裏作爲註釋?如果這是有效的代碼,「and VA_ARGS = __VA_ARGS__」是幹什麼的?謝謝。 – Virus721 2015-09-04 12:37:30

16

我貼the following Microsoft support issue

下面的程序提供了編譯錯誤,因爲預編譯 擴展__VA_ARGS__錯誤:

#include <stdio.h> 

#define A2(a1, a2) ((a1)+(a2)) 

#define A_VA(...) A2(__VA_ARGS__) 

int main(int argc, char *argv[]) 
{ 
    printf("%d\n", A_VA(1, 2)); 
    return 0; 
} 

預處理擴張printf爲: printf(「%d \ n」,((1,2)+())); (「%d \ n」,((1)+(2)));}}

我收到了以下答覆不滿意從微軟編譯器團隊開發:

喜:在Visual C++編譯器是正確在這種情況下表現。如果將在初始宏調用中匹配'...'的標記組合在一起以形成單個實體(16.3/p12)的規則與在參數替換之前展開子宏的規則(16.3.1/p1 ),那麼在這種情況下,編譯器認爲A2是用一個參數調用的:因此是錯誤消息。

+1

感謝傳遞MS的理由。他們似乎將16.3.1/p12中的「組合形成一個單一項目」解釋爲「組合形成一個永久不可分割的預處理器標記」,這看起來似乎不太有用。我期望至少爲16.3.4中給出的重新掃描步驟重新分離替換的令牌,這似乎是其他編譯器正在做的事情。 – jcl 2014-08-29 20:35:31

+0

我非常同意,但我顯然被GCC和Clang寵壞了。您是否可以考慮MSVC行爲的使用案例,還是僅僅爲了一致性而保持一致性,儘管可以表達?我很好,但是「......在這種情況下,編譯器*相信* ...」聽起來並不令人信服,更不用說試圖編寫不可知代碼的人。我有一些解決方法的想法,但我的Windows分區已經沒有佣金了。無論如何,我希望看到有人嘗試。對不起,咆哮和/或necropost。 – 2017-09-10 23:24:46

+1

FWIW,這是[另一個bug](https://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement)在同一問題上,團隊承認這是一個錯誤,但說它不是沒有足夠的優先權來解決(7年前)。 – BeeOnRope 2017-11-22 19:39:39

1

您使用的是什麼版本的MSVC?您將需要Visual C++ 2010.

__VA_ARGS__由C99首次引入。 MSVC從來沒有試圖支持C99,所以沒有增加支持。

但是,現在,__VA_ARGS__包含在新的C++標準C++ 2011(以前稱爲C++ 0x)中,微軟顯然計劃支持該標準,因此它在最新版本的MSVC中得到了支持。

順便說一句,您將需要使用.cpp後綴到您的源文件來獲得此支持。 MSVC很久沒有更新其C前端。