Stupid Coding Tricks

During a lunch interview, my interviewer wrote the following line of C/C++ code on a napkin:

 

a ^= b ^= a ^= b;

 

He then asked me what it does.  It was a bad question.  While we might expect it to swap the contents of a and b, the code relies on the results of intermediate subexpressions.  According to Stroustrup, The C++ Programming Language (2nd Ed.), section 6.2.2, “The order of evaluation of subexpressions within an expression is undefined.”  This is, in fact, a hold-over from Kernighan & Ritchie’s original definition in The C Programming Language (of which I don’t have a copy on hand, or I’d look it up—so the exercise is left for the reader).

 

It’s important to note that the compiler’s behavior is undefined as opposed to implementation defined, which means that you may well get the behavior you expect some times, yet there will be times when the behavior is something else.  For example, Metrowerks’ compilers give the expected results when both variables are allocated in registers, but produce a different result when the variables are allocated on the stack.

 

You’ll have to ask a compiler writer to get the details of the underlying reason for this, but it has to do with modern compiler issues like instruction scheduling, pipelining and attempting to get two processor instructions to execute simultaneously.  The important thing for programmers to understand is that different behaviors for the same line of code is not a compiler bug when the behavior is undefined.

 

We can resolve the undefined issue by using the comma operator:

 

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

 

But that doesn’t completely remove the stupidity of this programming trick.  It’s still obscure.  We could comment it whenever we use it, but that gets tedious.  One way to remove the obscurity is to use a macro:

 

        #define Swap(a, b) (a ^= b, b ^= a, a ^= b)

 

While that removes the obscurity of the code, there’s still one more problem with it.  Compilers have advanced to the point where the use of inline functions and global optimizations render this kind of programming trick completely unnecessary.  Worse yet, it can actually result in slower code than if you’d been more direct in your intent.

 

For example, consider the C++ way of doing this:

 

template <typename T>

inline void Swap (T &a, T &b)

{

        T c = b;

        b = a;

        a = c;

}

 

The actual code generated by the Metrowerks PowerPC compiler completely optimizes out both the call semantics and the use of any temporary variable.  In fact, the compiler merely makes any subsequent references to the location for variable a refer to the location that had originally been allocated for variable b, and vice-versa.  As far as the generated code is concerned, the call to the inline Swap function becomes a complete no-op.

 

So, not only is the XOR swap stupid because it’s obscure, it’s stupid because, with modern optimizing compilers, the eventual result often ends up being contrary to the intended result of using the coding trick in the first place.  The only benefit of the XOR version of the Swap macro is in C programs where we don’t have the benefit of templates.  The Swap macro provides a type-independent way of expressing the idea.  The price, however, would suggest that writing separate inline routines for each integral type for which it is needed would result in smaller, and faster, code.

 

The moral is, before you consider using some obscure coding trick for the sake of performance, write up some sample code, and take a look at the actual code your compiler generates.  More often than not, you’ll find that the less obscure method results in better code.

 

 

Rick