【发布时间】:2012-11-24 10:49:43
【问题描述】:
鉴于...
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++ 的行为,并假设我需要接受教育。我了解表达式评估逻辑的 HOW,不需要 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#