为啥 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?