鉴于...
int a = 1, b = 4;
然后……
a += b += a += b;
在 C++ 中求值...
(a += (b += (a += b))); // a = 14[5 + 9] (b = 9[4 + 5] (a = 5[1 + 4]))
... 在 C# 中...
(a += (b += (a += b))); // a = 10[1 + 9] (b = 9[4 + 5] (a = 5[1 + 4]))
// ^ re-use of original value of a (1)
// instead of expected intermediate right-to-left
// evaluation result (5)
以上内容已经在 Visual Studio 2008 和 2012 中进行了测试,因此不怀疑最近引入的语言错误。
但是,我确实希望 C# 的行为能够模仿 C++ 的行为,并假设我需要接受教育。我了解表达式评估逻辑的方式,不需要解释 MSIL。经过相当广泛的搜索并未能在语言规范中找到相关的细则,我希望语言专家能够解释为什么会这样。
对于想知道我到底为什么要这样做的好奇者......有一个非常有效和整洁的两个整数类型的内联交换的小 C++ 技巧,就像这样......
a ^= b ^= a ^= b;
我很失望地发现它在 C# 中不起作用,并且很好奇为什么。这是关于了解 C# 的低级机制及其背后的基本原理。不多不少,特别是没有可读性宗教。
注意
伙计们,这不是将所有内容都压缩到一条线上的认真努力!!!
对于 C(以及后来的 C++),运算符优先级和结合性一直被精确定义。
赋值运算符的标准从右到左关联性使 C/C++ 版本的行为 100% 清晰且可预测。它已经在多个编译器和平台上为我工作,我认为一个没有像这样运行的编译器是有问题的。
我承认代码行被混淆了,这是一种好奇心,用作我可能会给初级 C/C++ 程序员的“脑筋急转弯”。
显然 C# 是不同的 - 显然是故意如此。
我寻求对导致 C# 与其祖先语言之一的行为差异的设计考虑因素的解释。 即使是有根据的猜测也会受到欢迎。
已回答
感谢 Alexander Stepaniuk。
从从左到右计算操作数开始
a = 1 + theRest1 // (1)
theRest1 = b = 4 + theRest2 // (2)
theRest2 = a = 1 + 4 // (3)
(3) into (2): theRest1 = b = 4 + 5
(2) into (1): a = 1 + 9
“为什么”的解释将不胜感激。
但 C# 规范明确指出以上是正确的评估。
下面是我们可以(我认为)使用 2 个变量尽可能接近 C++ 技巧...
b ^= a ^= b;
a ^ = b;
我不喜欢它 - 郑重声明 - 因为它打破了我的直觉;-)
最佳答案
它也不能保证在 C/C++ 中工作。在单个语句中多次赋值的变量的值是未定义的。
它是否有效取决于实现 - 您可能会发现它根本不起作用的编译器或架构。
C# 只是对此很严格,这并不是坏事。
无论如何,xor 技巧在现代架构上毫无意义。底层实现的效率将低于仅使用临时变量。现代 CPU 上有 2 个以上的寄存器。
关于C# 在多重赋值中丢失中间值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13540480/