8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

MSVC 无法正确扩展 __VA_ARGS__

Tanas 1月前

134 0

考虑以下代码:#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,即

考虑以下代码:

#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 针对两个宏的,这就是我使用 GCC 获得的结果,但是,MSVC 将其扩展为:

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

也就是说, __VA_ARGS__ 它被扩展为一个参数,而不是分解为多个参数。

有什么办法可以解决这个问题吗?

帖子版权声明 1、本帖标题:MSVC 无法正确扩展 __VA_ARGS__
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Tanas在本站《visual-studio》版块原创发布, 转载请注明出处!
最新回复 (0)
  • /Zc:preprocess来解决 or /experimental:preprocessor 。有关详细信息,请参阅 此处 .

    MSVC 的预处理器的行为似乎与标准规范有很大不同。
    以下解决方法可能会有所帮助:

    #define EXPAND( x ) x
    #define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
    #define G(...) EXPAND( F(__VA_ARGS__) )
    
  • __VA_ARGS__ 还不是标准 C++ 的一部分。标准草案是否实际指定了这种情况下的行为应该是什么?

  • @bk1e:抱歉,由于我没有能力,我无法在这里详细解释即将出台的 C++ 标准中的预处理,但它不太可能与 C99 有太大不同。

  • 有人能解释一下吗? \'and VA_ARGS = VA_ARGS\' 是一段有效的 C 代码吗?还是只是一段人类可读的文本,作为注释?如果这是有效代码,那么 \'and VA_ARGS = VA_ARGS\' 是做什么的?谢谢。

  • 哦,我想我明白了……为了简单起见,我们假设 __VA_ARGS__ 是 1, 2。EXPAND(x) x 采用 F(__VA_ARGS__)) 并将其替换为 F(1, 2),以便处理 F(1, 2) 而不是 F(__VA_ARGS__),其中 __VA_ARGS__ 被视为单个实体(如果这有意义的话)……

  • @IseWisteria,@rbrich 已经在下面提到,现在有编译器开关 /Zc:preprocessor (参见此处),它将正确解压 __VA_ARGS__。也许值得编辑您的答案以将其包含在原始解决方案之外?

  • 我发布了 以下 Microsoft 支持问题 :

    以下程序由于预编译器扩展 __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)+()));

    而不是 printf(\'%d\n\', ((1)+(2)));

    我从微软编译器团队的开发人员那里得到了以下不令人满意的答案:

    您好:Visual C++ 编译器在这种情况下表现正常。如果将与初始宏调用中的“...”匹配的标记组合起来形成单个实体 (16.3/p12) 的规则与在参数替换之前扩展子宏的规则 (16.3.1/p1) 结合起来,那么在这种情况下,编译器会认为 A2 是使用单个参数调用的:因此出现错误消息。

  • 感谢您传达 MS 的理由。他们似乎将 16.3.1/p12 中的“合并形成单个项目”解释为“合并形成单个永久不可分割的预处理器标记”,这似乎不太有用。我希望替换的标记至少在 16.3.4 中给出的重新扫描步骤中重新分离,这似乎是其他编译器正在做的事情。

  • 我非常同意,但我显然被 GCC 和 Clang 宠坏了。你们俩能想到 MSVC 行为的用例吗,或者这只是为了一致性而一致性的问题,尽管具有可表达性?我完全不了解情况,但“...在这种情况下,编译器认为...”听起来不太有说服力,更不用说对任何试图编写不可知代码的人来说都没什么用了。我有一些解决方法,但我的 Windows 分区已经坏了。无论如何,我都想看看有人尝试一下。抱歉发牢骚和/或发帖。

  • 值得一提的是,这里还有关于同一问题的另一个错误,团队承认这是一个错误,但表示修复它的优先级不够高(7 年前)。

  • 引用 12

    现在有 /experimental:preprocessor 或 /Zc:preprocessor 编译器开关,可使预处理器正常运行。它为我解决了这个问题。

  • 您使用的是哪个版本的 MSVC?您需要 Visual C++ 2010。

    __VA_ARGS__ 由 C99 首次引入。MSVC 从未尝试支持 C99,因此未添加支持。

    然而,现在 __VA_ARGS__ 它已包含在新的 C++ 标准 C++2011(以前称为 C++0x)中,微软显然计划支持它,因此它已在 MSVC 的最新版本中得到支持。

    顺便说一句,您需要 .cpp 在源文件中添加后缀才能获得此支持。MSVC 很长时间没有更新其 C 前端了。

返回
作者最近主题: