About Blog Contact

Caveats when Using Swap in C

How do you swap the values of two variables? You could use a temporary variable:

tmp = a;
a = b;
b = tmp;

This is the safest and most straight forward way. Yet some people just can’t stand a few extra bytes used in RAM, so they would “optimize” it:

a = a + b;
b = a - b;
a = a - b;

Not to mention the potential overflow this might cause, it still makes very little improvement, replacing a load-store instruction with an arithmetic instruction, which might not be quicker, while making the code a whole lot less readable.

If it’s not readable, let’s make it a macro then!

#define SWAP(X,Y) do {(X) = (X) ^ (Y); (Y) = (Y) ^(X); (X) = (X) ^ (Y);} while(0)

It even uses bit arithmetic! This would be blazing fast! Well, lets try it out then:

int a[] = {0,1,2,3,4,5,6,7,8,9,10}; 
for(int i = 0; i <= 10 - i; i++) {
    SWAP(a[i], a[10-i]);
}
for(int i = 0; i < 10; i ++ ) {
    printf("%i ", a[i]);
}
printf("\n");

It reverses the array, so the result should be:

10 9 8 7 6 5 4 3 2 1 

right? Wrong! The actual output is:

10 9 8 7 6 0 4 3 2 1

Why is there a zero? Well, the code attempt to swap two variables with identical locations in memory:

SWAP(a[5], a[5]);

lets expand the macro:

do {(a[5]) = (a[5]) ^ (a[5]); (a[5]) = (a[5]) ^(a[5]); (a[5]) = (a[5]) ^ (a[5]);} while(0)

XORing a variable with self returns all zeros! So if such a macro is used to swap variables stored in the same place, it would simply zero them out! It wouldn’t be too difficult to spot the problem in the above code, but if you are using two pointers, then it might not be obvious.

So in conclusion, I don’t think using such fancy “optimizations” or “hacks” are beneficial. It would not speed up your code in any meaningful way, and meanwhile introducing subtle bugs like this one. Use std::swap, or just make a copy.