为啥 x++-+-++x 合法而 x++-+++x 不合法?

Posted

技术标签:

【中文标题】为啥 x++-+-++x 合法而 x++-+++x 不合法?【英文标题】:Why is x++-+-++x legal but x+++-+++x isn't?为什么 x++-+-++x 合法而 x++-+++x 不合法? 【发布时间】:2013-07-10 02:33:53 【问题描述】:

我想知道为什么在 C# 中以下内容很好:

int y = x++-+-++x;

但是

int y = x+++-+++x;

不是吗?为什么对 + 有偏见?

【问题讨论】:

更好的问题是你为什么要使用这个? 这取决于编译器(VS 2012 上的 .Net 4.5 抱怨) 我们需要详细说明您使用的编译器、您的目标是什么 .NET 等 是的,你为什么要使用这个? 这是一个完全合理的技术问题,其具体答案并不明显。它不应该因为离题而关闭。 【参考方案1】:

另外两个答案是正确的;我要补充一点,这说明了词法分析的一些基本原则:

词法分析器是短视的——它的“前瞻”极少 词法分析器是贪婪的——它试图现在生成最长的标记。 词法分析器不会在失败时回溯尝试寻找替代解决方案。

这些原则意味着+++x 将被解析为++ + x 而不是+ ++ x

然后解析器会将++ + x解析为++(+x),而(+x)不是一个变量,它是一个,所以不能递增。

另请参阅:http://blogs.msdn.com/b/ericlippert/archive/2010/10/11/10070831.aspx

【讨论】:

+1,虽然这会让 Mono 可以编译相同的代码很奇怪。要么规范在这方面有点“开放”,要么其中一个编译器不完全符合规范。 @JoachimIsaksson:Mono 有一个小错误;我怀疑它在语义分析器中,而不是词法分析器中。也就是说,不是 Mono 将 +++x 词法化为 + ++ x 的情况。相反,我怀疑它正确地将其词法分析为++ + x,然后语义分析器将+x 视为x,但忘记了+x 是一个值,而不是变量,因此不适合作为操作数的增量。 @JoachimIsaksson:确实。 Microsoft C# 编译器在 C# 2.0 中有许多此类错误;我在 C# 3.0 中删除了很多。我们保留了一些,因为它们是无害的,并且进行重大更改会造成破坏。【参考方案2】:

我正在使用 VS 2012。这很有趣。

第一个可以解析成:

int y = (x++) - (+(-(++x)));

不改变最终结果。所以你可以看到为什么它是有效的。

然而,第二个与+++x 存在问题,因为(我猜)它看到两个 ++ 并尝试将该一元运算符应用于 r 值,即另一个 +(而不是一个有效的 r 值)。 不过,您可以通过各种方式对其进行分组以使其发挥作用:

int y = (x++)+(-(+(++x)));

有效。

我相信 Jon Skeet 或 Eric Lippert 或其他人会出现并指出 C# 规范的相关部分。我什至不知道从哪里开始。但是只要按照一般的从左到右的标记解析,您就可以看到它会在第二个标记上阻塞。

【讨论】:

仅供参考,整个语法位于附录中规范的末尾。 在运算符语法上除了“one of”什么都看不到,在任何阶段是否更喜欢+++ 似乎都含糊不清。 @JoachimIsaksson:规范的第 2.3 节说 “当多个词法语法产生匹配源文件中的字符序列时,词法处理总是形成可能的最长词法元素。”我>【参考方案3】:

编译器正在寻找int y = x+++-+++x 中第二个++ 之后的变量或属性,如果没有空格或括号,则无法确定。

你可以这样做:

int y = x+++-+(++x); 

int y = x++ + -+ ++x;

如果你愿意。

您列出的第一个示例有效的原因是编译器可以从++x 中确定+-;而在第二个示例中,它无法确定将+++ 分开的位置,并且在读取第一个++ 后自然会期待一个变量;所以简而言之,编译器试图使用+x作为变量,这是无效的。

两者都可能在使用其他编译器时有效。这取决于语义。

【讨论】:

以上是关于为啥 x++-+-++x 合法而 x++-+++x 不合法?的主要内容,如果未能解决你的问题,请参考以下文章

为啥执行 exec('print(x)') 而 print(x) 在此 python 代码中出错?

为啥要使用三元运算符而不为“真”条件赋值 (x = x ?: 1)

为啥这段代码在 for 循环中只使用 x 而不是 x 和 y? [关闭]

为啥使用 static_cast<int>(x) 而不是 (int)x?

为啥 .WMV 文件的 mime 类型为“video/x-ms-asf”而不是“video/x-ms-wmv”?

为啥在这个例子中有“for(auto& x : v)”而不是“for(auto x : &v)”?