Visual Studio 中的预处理器不一致



我正在Visual Studio 2015(更新3(中编译以下C++代码:

#include <iostream>
using namespace std;
////////////////////////////////////////
#define UNDERSCORE1(a,b) a ## _ ## b
#define UNDERSCORE(a,b) UNDERSCORE1(a,b)
#define STRINGIFY1(x) #x
#define STRINGIFY(x) STRINGIFY1(x)
#define VALUE(x) UNDERSCORE(x, VALUE)
#define NEXT(x) (VALUE(x) + 1)
/////////////////////////////////////////
#define X1_VALUE 0
#define X2_VALUE NEXT(X1)
#define X3_VALUE NEXT(X2)
#define TOTAL NEXT(X3)
int main() {
cout << STRINGIFY(TOTAL) << endl;
cout << TOTAL << endl;
return 0;
}

打印到标准输出的结果非常奇怪:

(X3_VALUE + 1)
3

在 gcc 上尝试相同的操作时,构建失败(预期(。
当注释掉cout << TOTAL << endl;时,我得到了完全不同的东西:

(NEXT(X2) + 1)

实际上 gcc 行为是有意义的,因为NEXT宏是递归调用的:NEXT(X3)扩展到X3_VALUE,而又扩展到NEXT(X2),所以不执行NEXT宏的第二次展开(NEXT(X2)(。

没有意义的是Visual Studio的行为:

  • 当使用STRINGIFY打印宏TOTAL时,NEXT似乎扩展了两次以产生X3_VALUE
  • 编译宏TOTAL直接发送到cout时,NEXT一路扩展!好像预处理器运行多次以递归扩展NEXT.

我尝试的另一件事是使用/P编译器选项在 Visual Studio 中编译此代码,以获取预处理的代码:

int main() {
cout << "(X3_VALUE + 1)" << endl;
cout << (((0 + 1) + 1) + 1) << endl;
return 0;
}

  • 那么,正如我所怀疑的那样,它是Visual Studio预处理器中的错误吗?还是合法的未定义行为?
  • 也许这种行为可以被滥用来真正递归地扩展宏?我知道通过一些技巧可以实现有限的递归,但仅限于预定义的扫描次数。在这种情况下,我没有观察到NEXT扩展次数的限制。

正如Hans在评论中提到的,MSVC预处理器不符合要求。

您可以使用-experimental:preprocessor启用一致性预处理器。

下面是一个简化的重现 + 解决方案: https://godbolt.org/z/7u_-bH

相关内容

  • 没有找到相关文章

最新更新