C# XOR Compiler ‘Error’

I may as well start with my pet peeve… The C# compilers failure to generate correct code for the following expression:

a ^= b ^= a ^= b;

Before C#, I (and many others, I’m sure) used that in C. For those who are not familiar with that expression, it basically swaps the variables a and b. They’re usually a numeric type.

So, way back in 2003 (using Visual Studio 2003), some friends and I were testing out swap functions to see which one was the fastest, and I tried this XOR swap. I took notice when I started getting bizarre results. You can try it out for yourselves.

Now, let’s take a look at the generated code (x86) for that expression:

			mov         eax,dword ptr [ebp-44h] 
			mov         dword ptr [ebp-4Ch],eax 
			mov         eax,dword ptr [ebp-48h] 
			xor         dword ptr [ebp-44h],eax 
			mov         eax,dword ptr [ebp-44h] 
			xor         dword ptr [ebp-48h],eax 
			mov         eax,dword ptr [ebp-4Ch] 
			xor         eax,dword ptr [ebp-48h] 
			mov         dword ptr [ebp-44h],eax

And if you translate that back into C# (or C for that matter), it is:

			temp = a;
			a ^= b;
			b ^= a;
			temp ^= b;
			a = temp;

As you can see, the compiler makes use of a temp variable, and it basically makes a mistake with it. In the assembly above, it makes the mistake at line 7. It used the initial value of a which it saved in the beginning instead of the new value by the earlier XOR operations. By the time it gets to that last XOR, b already has the value of a, and therefore results in a zero instead of a correct swap.

Others have encountered this, and there has been some debate about how C# evaluates such expressions. Regardless, such expressions have to be evaluated from right-to-left. However, it seems the compiler uses the ‘old’ values for the left operand, and just by luck, it got the first b (from the left) XOR right as it wasn’t modified in the first XOR operation (right most). So how did the Microsoft C compiler get it right? Because it uses the latest values for a and b each time one of the XOR’s is processed. This is the correct way to do it, and you would then get the results you expect.

Therefore, if this is a ‘feature’, it’s hard to say it is a good one by any stretch of the imagination. It must be a bug. And not only that, it is still there in Visual Studio 2010. I can understand that this is a low priority issue if it is indeed a bug as it can be easily worked around by breaking up the expression into the more obvious:

			a ^= b;
			b ^= a;
			a ^= b;

Don’t you just love it when it ain’t your fault?

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s