Why am i ^ = j ^ = i ^ = j is not equal * i ^ = * j ^ = * i ^ = * j

In C, when there are variables (suppose that as int ) i less than j , we can use the equation

 i^=j^=i^=j 

to exchange the values โ€‹โ€‹of two variables. For example, let int i = 3 , j = 5 ; after the calculated i^=j^=i^=j , I have i = 5 , j = 3 .

However, if I use two int pointers to redo this, *i^=*j^=*i^=*j using the example above, what I will have is i = 0 and j = 3 .

<h / "> In C

1

  int i=3, j=5; i^=j^=i^=j; // after this i = 5, j=3 

2

  int i = 3, j= 5; int *pi = &i, *pj = &j; *pi^=*pj^=*pi^=*pj; // after this, $pi = 0, *pj = 5 

In javascript

  var i=3, j=5; i^=j^=i^=j; // after this, i = 0, j= 3 

JavaScript result makes it more interesting for me

my sample code is on ubuntu 11.0 server and gcc

  #include <stdio.h> int main(){ int i=7, j=9; int *pi=&i, *pj=&j; i^=j^=i^=j; printf("i=%dj=%d\n", i, j); i=7, j=9; *pi^=*pj^=*pi^=*pj printf("i=%dj=%d\n", *pi, *pj); } 

<h / ">

undefined behavior in c

Will undefined behavior in c be the real reason leading to this question?

1

the compiled code uses visual studio 2005 on Windows 7 to get the expected result (output i = 7, j = 9 twice).

2

compiled code using gcc on ubuntu ( gcc test.c ) produces an unexpected result (output i = 7, j = 9, then i = 0, j = 9)

3

the compiled code uses gcc on ubuntu ( gcc -O test.c ), gives the expected result (output i = 7, j = 9 twice).

+4
source share
3 answers

i^=j^=i^=j is undefined behavior in C.

You break the rules of the queue points by changing i twice between two points in the sequence.

This means that the implementation can freely assign any value or even cause failures in your program.

For the same reason, *i^=*j^=*i^=*j also undefined.

(C99, 6.5p2) "Between the previous and next point in the sequence, the object must have its stored value, changed no more than once by evaluating the expression."

+8
source

Consider the following code:

  #include <stdio.h> int main() { int i=7, j=9; int *pi=&i, *pj=&j; i^=j^=i^=j; printf("i=%dj=%d\n", i, j); i=7, j=9; *pi^=*pj^=*pi^=*pj; printf("i=%dj=%d\n", *pi, *pj); return 0; } 

If you try to compile it, you will see warning: unsequenced modification for the first line. As @ouath said this is undefined. According to C11 Standard , assignment expressions work in the read-modify-write mode. This operation is not atomic for all CPU architectures. You can read more about the warning here .

It is interesting to see that for *pi^=*pj^=*pi^=*pj; there are no warnings in my LLVM compiler.

+4
source

Regarding the โ€œmore interestingโ€ aspect added by the Javascript result:

While the expression is undefined in C as described in ouah's answer , it is well defined in Javascript. However, the rules for how an expression is evaluated in Javascript may not be what you expect.

The ECMAscript specification states that a complex assignment operator is computed as follows (ECMA-262 11.13.2):

Output Assignment production: LeftHandSideExpression @= Assignment highlighting, where @ represents one of the statements above, is evaluated as follows:

  • Calculate the value of LeftHandSideExpression.
  • Call GetValue (Result (1)).
  • Calculate the assignment.
  • Call GetValue (Result (3)).
  • Apply the @ operator to result (2) and result (4).
  • Call PutValue (Result (1), Result (5)).
  • Return Result (5).

So, the expression i ^= j ^= i ^= j will be evaluated in the following steps:

 i = (3 ^ (j ^= i ^= j)) i = (3 ^ (j = (5 ^ i ^= j))) i = (3 ^ (j = (5 ^ (i = 3 ^ j))))) i = (3 ^ (j = (5 ^ (i = 3 ^ 5))))) i = (3 ^ (j = (5 ^ (i = 6))))) i = (3 ^ (j = (5 ^ 6)))) i = (3 ^ (j = 3)) // j is set to 3 i = (3 ^ 3) i = 0 // i is set to 0 

Another reason to avoid the trick of using the xor operation to replace values.

+3
source

Source: https://habr.com/ru/post/1433138/


All Articles