C ++预处理器中R和L有什么特别之处?

时间:2014-01-13 18:19:22

标签: c++ visual-c++ c++11 c-preprocessor compiler-bug

我通过Visual Studio 2013预处理器运行以下代码。输出令我惊讶。

hello.cpp的内容:

#define A(j) #j

A(A?)
A(B?)
A(C?)
A(D?)
A(E?)
A(F?)
A(G?)
A(H?)
A(I?)
A(J?)
A(K?)
A(L?)
A(M?)
A(N?)
A(O?)
A(P?)
A(Q?)
A(R?)
A(S?)
A(T?)
A(U?)
A(V?)
A(W?)
A(X?)
A(Y?)
A(Z?)

命令:

cl /P hello.cpp

hello.i包含:

#line 1 "hello.cpp"



"A?"
"B?"
"C?"
"D?"
"E?"
"F?"
"G?"
"H?"
"I?"
"J?"
"K?"
"L"
"M?"
"N?"
"O?"
"P?"
"Q?"
"R"
"S?"
"T?"
"U?"
"V?"
"W?"
"X?"
"Y?"
"Z?"

我试图打电话给A(L?p:q)时遇到了这个问题,这导致了“Lp:q”,这对我不利。

这是正确的,定义明确的C ++吗? C ++中的L和R有什么特别之处?如果文件具有.c扩展名,则L和R被视为与字母表的其余部分相同。这与C ++ 11有关吗?它必须是一个新功能,因为旧版本的MSVS不会以特殊方式使用L和R.

我该怎样做才能阻止MSVS 2013以这种特殊的方式治疗L和R?

2 个答案:

答案 0 :(得分:20)

更新

看起来错误报告被标记为this one的副本,其中包含更新内容:

  

此问题的修复程序已检入编译器源。修复程序应该出现在Visual C ++的下一个主要版本中。

原始

正如雷米亚贝尔指出这是一个reported bug。根据{{​​1}}文档,gccclang都不会产生此结果和stringizing operator #,这些是以下替代品(强调我的前进):

  

忽略实际参数的第一个标记之前和实际参数的最后一个标记之前的空格。实际参数中的标记之间的任何空格都会缩减为生成的字符串文字中的单个空格。因此,如果在实际参数中的两个标记之间发生注释,则会将其缩减为单个空格。生成的字符串文字会自动与任何相邻的字符串文字连接,只能用空格分隔。

     

此外,如果参数中包含的字符在字符串文字中使用时通常需要转义序列(例如,引号(“)或反斜杠()字符),则必须在字符前插入必要的转义反斜杠。

对应C++ draft standard部分Visual Studios #运算符,其中包含:

  

如果在替换列表中,参数前面紧跟#预处理标记,则两个都被单个字符串文字预处理标记替换,该标记包含相应的预处理标记序列的拼写   论点。参数的预处理标记之间每次出现的空格都会成为字符串文字中的单个空格字符。在第一个预处理标记之前和包含该参数的最后一个预处理标记之后的空格被删除。否则,参数中每个预处理标记的原始拼写都保留在字符串文字中,除了用于生成字符串文字和字符文字的拼写的特殊处理:在字符文字的每个“和\”字符之前插入\字符或字符串文字(包括分隔“字符”。

与{em> C ++ 11 相关的16.3.2R唯一的一点是它们与string literals有特殊含义,但我不是看看这应该如何影响这种情况。

看起来LL\也会产生同样的问题。

他们会记录一个non-compliant issue,并说:

  

当#(stringize)运算符与包含转义序列的字符串一起使用时,Visual C ++的行为不正确。在这种情况下,编译器将生成编译器错误C2017。

不包括这种情况。

答案 1 :(得分:3)

这似乎是MSVC预处理器中的错误。好消息是,根据您对输出的挑剔程度,您可以通过在R或L之后放置一个空格来解决问题。

A(L ?p:q), // "L ?p:q"