2

I always thought that A ^= B ^= A ^= B swaps A <-> B. My guess that this line should be evaluated right to left in 3 steps:

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

But somehow in C# A becomes 0 if you do it in one line. I've looked into the assembly and found that original A is being stored first and somewhy in the last third step instead of taking the actual current value of A, the code uses cached original value. Assembly looks like this:

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)

It seems ok in C++ and assembly is using only 2 variables:

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

Am I missing something?

Empted
  • 41
  • 3

1 Answers1

2

In C++ this would be an undefined behavior* because of multiple unsequenced assignments.

In C# this is perfectly valid, and zero is the correct result.

To see why consider that XOR ing any number with itself yields zero, because at each sport in the bit pattern there are equal bits. Moreover, XOR order is not important. That's why B ends up with the old value of A, and A ends up being zero.

* prior to C++ 17, anyway.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523