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?