A ^= B ^= A ^= B;C# Visual Studio 中的意外结果

A ^= B ^= A ^= B; unexpected result in c# visual studio

本文关键字:意外 结果 Visual Studio      更新时间:2023-10-16

我一直认为 A ^= B ^=A ^= B 交换 A <-> B。我猜这条线应该分 3 个步骤从右到左评估:

1) A ^= B;
2) B ^= A;
3) A ^= B;

但是在 C# 中,如果你在一行中这样做,A 会变成 0。我查看了程序集,发现原始 A 首先被存储,为什么在最后第三步中,代码使用缓存的原始值,而不是采用 A 的实际当前值。程序集如下所示:

mov         eax,dword ptr [ebp-40h]  //eax <- A
mov         dword ptr [ebp-7Ch],eax  //C <- A (why cache?)
mov         eax,dword ptr [ebp-44h]  //eax <- B
xor         dword ptr [ebp-40h],eax  //A ^= B
mov         eax,dword ptr [ebp-40h]  //eax <- A
xor         dword ptr [ebp-44h],eax  //B ^= A
mov         eax,dword ptr [ebp-7Ch]  //eax <- C (?)
xor         eax,dword ptr [ebp-44h]  //eax ^= B (= C ^ B)
mov         dword ptr [ebp-40h],eax  //A = C ^ B (instead of A ^ B)

C++似乎还可以,程序集仅使用 2 个变量:

mov         eax,dword ptr [a]
xor         eax,dword ptr [b]
mov         dword ptr [a],eax
mov         ecx,dword ptr [b]
xor         ecx,dword ptr [a]
mov         dword ptr [b],ecx
mov         edx,dword ptr [a]
xor         edx,dword ptr [b]
mov         dword ptr [a],edx

我错过了什么吗?

在C++中,由于多个未排序的赋值,这将是一个未定义的行为*

在 C# 中,这是完全有效的,零是正确的结果。

要了解为什么考虑将任何数字与自身进行异或运算都会产生零,因为在位模式中的每个运动中都有相等的位。此外,异或顺序并不重要。这就是为什么 B 最终得到 A 的旧值,而 A 最终为零。

*无论如何,在 C++ 17 之前。