4

I was asked to write a swap without using temp variables or using xor and i came up with this.
In Java, this works, but in C/C++ this does not work.

I was under the impression that this would always work since the value of 'a' on the left side of the '|' would be stored in a register and then the assignment to 'a' would occur negating the effect on the assigned value for 'b'.

int a = 5;
int b = -13;
b = a | (0 & (a = b));
maksimov
  • 5,792
  • 1
  • 30
  • 38
HBP
  • 51
  • 4
  • 6
    Is the lack of temporary variable *really* worth the massive drop in readability? – Platinum Azure Jun 20 '12 at 15:02
  • Well, in C++ it's not "stored in a register" obviously – Mooing Duck Jun 20 '12 at 15:03
  • 1
    Could it be, that the compiler optimizes the code and removes the `0*(a=b)`stuff? – lhlmgr Jun 20 '12 at 15:04
  • 4
    @PlatinumAzure it's a standard exercise. Obviously nobody would put this in real code. – MK. Jun 20 '12 at 15:04
  • @PlatinumAzure: It's a _puzzler_, it is _ment_ to be unreadable ;-) – npe Jun 20 '12 at 15:07
  • 1
    You are not quite on the right track in solving this. This work or doesn't work depending on language internals and undefined (or poorly defined behaviors). Try to think about the problem in a more mathematical way. The solution is intuitive (once you see it) and will work in any language. – MK. Jun 20 '12 at 15:14
  • I know the solution using math, i was more interested in understanding why this solution doesn't always work. – HBP Jun 20 '12 at 15:25
  • @user1469615 if you do then just program it. It doesn't require the assignment trick :) – MK. Jun 20 '12 at 15:26
  • this isn't a real world situation at all. it was born out of curiosity and reducing the runtime of the math solution. – HBP Jun 20 '12 at 15:28

3 Answers3

10

You are modifying a variable and reading its value without an intervening sequence point.

b =         a          + 0 *   (a = b);
//  reading a's value        modifying a

This is undefined behavior. You have no right to any expectations on what the code will do.

Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
  • @user1469615: Read [this](http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points) and [this](http://stackoverflow.com/questions/4638364/undefined-behavior-and-sequence-points-reloaded) – Benjamin Lindley Jun 20 '12 at 15:20
2

The C/C++ compiler optimizes the expression 0 * (a = b) to simply 0 which turns your code fragment into:

int a = 5;
int b = -13;
b = a;
Simeon Visser
  • 118,920
  • 18
  • 185
  • 180
  • I wonder if it would make a difference if it was instead, `b = a + ((a=b) * 0)`? Because it should see the a=b before looking at the * 0. Maybe I should give it a try... – Sephallia Jun 20 '12 at 15:08
  • 1
    @Sephallia: No, it won't get confused. – Puppy Jun 20 '12 at 15:13
  • I gave it a shot, and the results are inline with @PeterLawrey 's answer. http://ideone.com/6sO8U – Sephallia Jun 20 '12 at 15:16
  • 3
    That's wrong: optimisation can't remove side-effects such as assignment (except in a very few cases such as copy elision, which doesn't apply here). The problem is that the modification of `a` and the use of its value are unsequenced, giving undefined behaviour. – Mike Seymour Jun 20 '12 at 15:35
1

In C/C++, assigment are performed in the order of expression. In Java, assignments occur last regardless of other expressions.

e.g. This increments in C but does nothing in Java.

a = a++;
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 4
    Wrong: in C and C++, the evaluation and side effects of sub-expressions happen in an unspecified order (unless there are sequence points, but there aren't any here). That expression doesn't (necessarily) increment in C; it has undefined behaviour. – Mike Seymour Jun 20 '12 at 15:37