诠释 x = 10; x += x--;在.Net - 为啥?
Posted
技术标签:
【中文标题】诠释 x = 10; x += x--;在.Net - 为啥?【英文标题】:int x = 10; x += x--; in .Net - Why?诠释 x = 10; x += x--;在.Net - 为什么? 【发布时间】:2011-01-18 22:58:57 【问题描述】:int x = 10;
x += x--;
在 C#/.Net 中,为什么它等于它等于什么? (我特意把答案漏掉了,让你猜猜看你是不是对的)
【问题讨论】:
它的行为方式是因为你不应该做这样的事情,因此这种行为是无关紧要的。 我不应该再猜测自己。似乎很明显,直到我想了一秒钟。我认为 20 的理由是,直到引用之后才发生递减,然后我开始笨拙地认为当操作完成时原始引用会递减,但它是一个值类型,但我猜 19。我很傻。 @Stefan - 对一门语言有深入的理解并不是无关紧要的,即使你总是写出好的代码。您可能不会运用全部知识,但当有人需要帮助时,您会更有信心。 在 Jon Skeets 解释之后,我很想知道有多少编译器会优化 --。 这样的问题应该被称为飞碟……非常适合飞碟射击。 【参考方案1】:来自specs 7.13.2
如果所选运算符的返回类型可隐式转换为 x 的类型,则该运算的计算结果为 x = x op y,但 x 仅计算一次。
所以你的陈述等同于x = x + x--;
,它按从左到右的顺序进行评估并给出答案 20。
注意这里--x
和x--
也有区别。如果你写了x += --x;
,这将等同于x = x + --x
;那么你会得到 19。这是因为 x 的值递减并且结果值在表达式中使用(不像 x--
在表达式中使用 x 的原始值)。
这个表达式x = x + --x + x
将给出 28,因为 第三次第四次(参见 cmets)x 被评估为 9。
【讨论】:
也许你的意思是20? 10 真的很令人惊讶..;) @Francesco:错字,已修复。现在我又添加了一个段落,而 that 10 实际上是 10。 虽然您在上一段中得出的答案是正确的,但您的解释并不完全合理。减量不能在之前 x 被评估,因为显然减量计算的值取决于x 的评估!相反,正确的说法是表达式 --x 的值是在减量之后分配给 x 的值。也就是说,事件的顺序是:计算 x (10),再次计算 x (10),减一 (9),将 9 赋值给 x,将 10 和 9 相加 (19),将 19 赋值给 x。 x 有两个评估,它们都发生在前面。 @Eric:是的,你是对的——“评估”这个词在这里用错了。感谢您的更正。我已经用我自己的话改写了。希望现在没事。 更好,但仍不完美。您的意思是在“x=x+--x+x”中计算 x 的 第四次 次,它是 9。首先在 = 的左侧计算 x 以确定存储的位置;这没有副作用,没有使用它的值,但它是一个评估。然后在 = 的右边求值为 10。再求值为 10,计算 10-1,将 9 赋给 x,9 为运算结果。然后,第四次评估 x,现在是 9。【参考方案2】:乔恩当然是对的。
思考这个问题的一个好方法是记住:
1) 子表达式总是被计算从左到右。时期。评估子表达式可能会引起副作用。
2) 运算符的执行始终按照括号、优先级和关联性指示的顺序进行。执行运算符可能会产生副作用。
+= 左边的“x”是最左边的子表达式,因此适用规则 (1)。首先计算它的值——10。
+= 右边的 x-- 是按从左到右的顺序排列的下一个,因此接下来对其求值。 x--的值是10,副作用是x变成9。这是理所当然的,因为--的优先级高于+=,所以它的副作用先运行。
最后,+= 的副作用最后运行。两个操作数是 10 和 10,所以结果是把 20 赋给 x。
我一直收到有关此的问题。请记住,规则非常简单:从左到右的子表达式、优先顺序的运算符、句点。
请特别注意,通常所说的“-- 运算符是后缀,因此在其他所有内容之后运行”的推理是不正确的推理。我将在下面的文章中讨论为什么这是不正确的。
这里有一些我写过的关于这个主题的文章:
http://blogs.msdn.com/ericlippert/archive/tags/precedence/default.aspx
【讨论】:
加法是C#中的一个序列点?您允许人们在不了解序列点的情况下编写代码。世界末日肯定就在眼前。【参考方案3】:答案是 20。汤姆,你真的并不像你的问题所暗示的那样感到惊讶,对吧?对于那些假设答案是 19 的人——我认为你对 x += --x; 感到困惑;
【讨论】:
他们困惑的可能不是--x,而是“减x”的副作用是发生在+=运算符左侧的计算之前还是之后.在 x+=x-- 从右到左计算的语言中,您首先计算 x--,即 10,然后将 9 分配给 x。然后计算左侧,现在是 9。现在将 9 加到 10 并将其分配给 x,因此,19。C# 保证表达式是从左到右计算的。 C++ 没有;如果选择,C++ 编译器可以从右到左求值,并且 19 和 20 都是合法结果。【参考方案4】:20;直到所有内容都被评估之后,“--”才会发生,并且该值被等号的左侧覆盖。
【讨论】:
虽然你得到了正确的答案,但让你到达那里的逻辑是不正确的。 “直到所有事情都得到评估之后才会发生”是误导性的。特别是,递减发生在将 9 分配给 x 之前,这发生在添加 10 和 10 之前,这发生在将 20 分配给 x 之前。减量的计算发生在一次加法和两次赋值之前,因此说它在 everything 被评估之前不会发生是不正确的。【参考方案5】:看看这句话:
x += x--;
这相当于:
x = x + x--;
相当于:
int a1 = x; // a1 = 10, x = 10
int a2 = x--; // a2 = 10, x = 9
x = a1 + a2; // x = 20
所以x
之后是 20 - 这是规范所保证的。
也几乎可以保证,尽管没有规范,但任何使用此类代码的人都会受到同事的攻击。是的,结果是可以预测的,这很好。不,使用那种代码不好。
【讨论】:
不公平...不应允许 Skeet 回答这些问题。 :P @CAbbott - 不幸的是,似乎没有其他人理解 x-- 和 --x 之间的区别! @Tom:是的,我做到了。我后来检查了它,诚然。我确实必须检查您是否将x
指定为int
,但如果x
是byte
,第一个“等效于...”会略有不同,即使结果是在这种情况下也是如此。
@Justin:是的,这保证会产生 19 - 扩展中 a2 的值将是 9。如果将其更改为 x = --x + x;
,则可以达到 18。
+1 表示“...任何使用此类代码的人都会受到同事的攻击...”以上是关于诠释 x = 10; x += x--;在.Net - 为啥?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 .NET 6 / C# 10 中将 List<String?> 转换为 List<String>?
如何在 mac os x (10.9) 上的 python 中安装 libgpuarray 和 clBLAS?
.Net Framework 4.x 程序到底运行在哪个 CLR 版本之上