2011-02-27 93 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前端。