Potential Problem in “Swapping values of two varia

2019-01-11 22:31发布

问题:

I recently came along this method for swapping the values of two variables without using a third variable.

a^=b^=a^=b

But when I tried the above code on different compilers, I got different results, some gave correct results, some didn't.

Is anything terribly wrong with the code?

回答1:

Is anything terribly wrong with the code?

Yes!

a^=b^=a^=b in fact invokes Undefined Behaviour in C and in C++ because you are trying to change the value of a more than once between two sequence points.


Try writing (although not foolproof )

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

instead of a^=b^=a^=b.

P.S : Never try to swap the values of two variables without using a third one. Always use a third variable.

EDIT :

As @caf noticed b^=a^=b is fine even though the order of evaluation of arguments of ^= operator is unspecified, since all the accesses of b within the expression are being used to compute the final value that is being stored in b, the behaviour is well defined.



回答2:

If you're using C++, why not use the swap algorithm in STL? It is ideal for this purpose and it's very clear what it does:

#include <algorithm>
using namespace std;

// ...

int x=5, y=10;    // x:5 y:10
swap(x,y);        // x:10 y:5


回答3:

Based on contributions from R. & sellibitze:

Use the comma operator:

 (a^=b,b^=a,a^=b);

From text & Wikipedia:

"The comma operator can be used to link the related expressions together. A comma-linked list of expressions is evaluated left-to-right and the value of the rightmost expression is the value of the combined expression. It acts as a sequence point."

"A sequence point guarantees that all side effects of previous evaluations will have been performed, and no side effects from subsequent evaluations have yet been performed. It removes the undefined behavior arising out of the unclear order of execution of the original expression."



回答4:

I suggest that you use std::swap() for c++.

For c, use this macro. Notice that you need to compare a and b first, otherwise when they are point to the same memory location you will wipe out the value and it becomes 0.

#define swap(a, b)  ((a) == (b) || (a) ^= (b), (b) ^= (a), (a) ^= (b))


回答5:

Do it like this:

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


回答6:

What about this one?

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


回答7:

I wondered why nobody suggested parenthesizing the expression. Seems it's not UB anymore.

a^=(b^=(a^=b));


回答8:

You can try the following one also, but if to numbers are large enough value will overflow

a=a*b;
b=a/b;
a=a/b;