两个相邻的##运算符

Art*_*tur 13 c c++ c-preprocessor

有人可以解释为什么2个连接运算符不会由预处理器产生任何错误吗?:

#define Z(x) x ## ## 3
Z(3)
Run Code Online (Sandbox Code Playgroud)

结果是:

33
Run Code Online (Sandbox Code Playgroud)

标准说:

...删除替换列表中的##预处理标记的每个实例(不是来自参数),并将前面的预处理标记与以下预处理标记连接在一起

所以我希望preprocesor首先尝试连接x第二个##看起来很奇怪的东西.这不会产生任何有效的令牌,所以我希望至少有一个警告.gcc和VC都没有发出任何警告.

我会很感激这是如何工作的原因和原因.标准提到了placemaker临时代币,这可以解释为什么这样做有效,但两个'双锐利'之间必须有一个这样的标记.问题是placemaker当参数不包含令牌且两个concat运算符之间没有参数时,会生成令牌.

ric*_*ici 3

(C 和 C++ 标准分别在 §6.10.3.3 和 §16.3.3 中具有基本相同的措辞。如果存在细微差异,我引用了 C11 中的内容。)

运算符的处理顺序##未明确指定:(“## 运算符的求值顺序未指定。”,第 3 段的最后一句;另请参阅上一节的第 2 段)。所以你不能说“预处理器首先尝试将 x 与第二个 ## 连接”;它可能首先尝试将第一个##3. 这也不会产生有效的令牌,所以这有点狡辩。但记住这一点很重要。

The question is whether the statement that the order of evaluation being unspecified permits the evaluation to be interleaved. In other words, could a preprocessor satisfy the standard by first deleting the second ##, then deleting the first one, and finally producing a single concatenation? Certainly, in the execution model, it is clear that unsequenced operations are allowed to interleave. (See note 13 in §5.1.2.3. In C++, the words are "can overlap"; §1.9/13)

That might be a bit of a stretch, but it's also worth noting that after concatenation:

If the result is not a valid preprocessing token, the behavior is undefined.

This is not marked as a constraint, so an error message is not required. And since undefined behaviour relieves the compiler from any obligation to the standard, I suppose gcc is totally within its rights to produce the observed behaviour.

In short, the macro replacement string provided in the original question either involves unspecified or undefined behaviour, but not a constraint violation. Consequently, the compiler is under no obligation to produce a diagnostic.

在这种情况下不产生诊断可能会被视为实施质量问题。另一方面,我不知道有哪个编译器会对##评估顺序不明确的宏产生警告。除了宏扩展列表不能以标记开始或结束(##必须由编译器诊断)的限制之外,确保串联表达式定义明确是程序员的全部责任。

  • @arnevogel:中间令牌可能对某些订单无效。`2e ## + ## 7` (2认同)