0

I've found the following code snippet:

#include <stdio.h>

int main(void) {
    int x=10,y=15;
    x=x+y-(y=x);
    printf("x=%d y=%d",x,y);
    return 0;
}

It actually swaps the variables

Can anybody explain me how the the code swaps the variable?

I thought the bracket would execute first and then expression leads to

x=x+y-y;
TryinHard
  • 4,078
  • 3
  • 28
  • 54

3 Answers3

6

This algorithm does not work because it invokes undefined behavior on this line:

x=x+y-(y=x);
    ^  ^

You are modifying y and also using its value within the same sequence point as per section 6.5 of the draft C99 standard:

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression.72) Furthermore, the prior value shall be read only to determine the value to be stored.73)

There is also the matter of unspecified behavior since the order of evaluation of the sub-expressions is unspecified:

The grouping of operators and operands is indicated by the syntax.74) Except as specified later (for the function-call (), &&, ||, ?:, and comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified.

In this case if you were using clang it would have provided the following warning:

warning: unsequenced modification and access to 'y' [-Wunsequenced]
x=x+y-(y=x);
    ~   ^

as far as I can tell by default. You can receive a similar warning from gcc by using -Wall.

There are several SO questions that cover how to swap without a temporary for example Swapping two variable value without using 3rd variable.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • 1
    An extra point worth mentioning is that there are two other ways of doing this: either a dedicated platform-specific instruction, or the "xor swap trick". The former is not portable/standard, and the latter is not safe. – Cloud Jul 17 '14 at 20:27
  • 1
    The xor swap trick is safe if you manually introduce sequence points, i.e. `x^=y;y^=x;x^=y;`, but you're probably better off just using a third variable anyway. (this of course assumes the variables are integer types). – Drew McGowen Jul 17 '14 at 20:30
2

This is actually a result of undefined behavior, due to something called sequence points. Basically, in this case, the C standard does not require the values to be stored in any order during evaluation of the expression. In fact, the following is certainly possible:

  1. Evaluate y = x, and store the value in y. In this case, x is still 10, and y is now also 10. The expression itself evaluates to 10 (the left-hand side of the assignment).
  2. Evaluate x = x + y - (y = x), which equates to x = x + y - 10. x and y are both 10, so this is x = 10 + 10 - 10, so x is now 10.

Now, x and y are both 10, and the original value 15 is now lost.

Edit: as far as how it can swap, it could be due to the optimization:

  1. Evaluate y = x, but don't store the value in y yet. y then still holds the value 15, whilst the assignment expression evaluates to 10.
  2. Now, x = x + y - 10 evaluates to x = 10 + 15 - 10, yielding the correct value.

Both scenarios are valid, but produce different results.

Drew McGowen
  • 11,471
  • 1
  • 31
  • 57
  • It doesn't have to be an optimization; it just performs the `x + y` bit first. I.e., `x = 10 + 15 - (y = 10);`. So it's undefined behavior, yes, but it's not due to any optimization that it happens to work on some compilers. – wolfPack88 Jul 17 '14 at 20:50
  • But such an optimization *can* happen; that's the whole point of UB. – Drew McGowen Jul 17 '14 at 20:51
  • Yes, it can; just wanted to point out another alternative that you had left out. – wolfPack88 Jul 17 '14 at 20:52
  • There's probably many more alternatives, I just wanted to point out two that had different results – Drew McGowen Jul 17 '14 at 20:57
2

I thought the bracket would execute first ...

That's an invalid assumption. Parentheses effect the precedence of operators in an expression. They do not specify order of execution. In

 a = b + c + (d * e);

it may well be that b + c is computed before (d * e). Or it may not. The C language standard leaves the order of evaluation of the sub expression unspecified. The code you posted invokes undefined behavior due to y being read and written to without an intervening sequence point. Note again that parentheses do not introduce sequence points (the semicolon does).

Jens
  • 69,818
  • 15
  • 125
  • 179
  • 1
    @FiddlingBits, They are the same for many people, including me. I tend to use square brackets and parentheses respectively, though. – chris Jul 17 '14 at 20:27
  • @AndrewMedico, I feel out of place as a Canadian now, but that happens with every American vs. British debate, so meh. – chris Jul 17 '14 at 20:35