Empted Empted - 3 months ago 12
C# Question

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

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?

Answer Source

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, ans A ends up being zero.