I typed the following program:
#include <stdio.h>
int main(void) {
int a = 3;
int b = 42;
printf("a = %d\nb = %d\n", a, b);
printf("Exchanging values.\n");
a ^= b ^= a ^= b;
printf("a = %d\nb = %d\n", a, b);
return 0;
}
and it's ok. When I try to compile it, I get this:
$ gcc test.c -o test -Wall -Wextra -ansi -pedantic-errors
test.c: In function ‘main’:
test.c:11: warning: operation on ‘a’ may be undefined
That's pretty much standard code, isn't it?
Why does it trigger a warning? As far as I know, bitwise XOR is implemented by default for int
as long as you are using a standard implementation of C.
Thank you very much.
a ^= b ^= a ^= b;
invokes Undefined Behaviour. You should use this:Variable
a
is used as an lvalue twice in the expression.Keep in mind that
x ^= y
is in fact a shortcut forx = x ^ y
, and it means that the first operand is read, then written.If you take the first operation out from the original expression, it is fine, see:
Here,
a
is used twice andb
is used three times. Since the assignment operator is right-to-left associative, firsta ^= b
is calculated, variableb
is only read, variablea
is read and then written, and the result (r1) is passed to the second operation. On the second operation,b ^= r1
,b
is read a second time (giving the same value as read previously) and then written. Note there is no way to interpret differently, no undefined behavior. In the above statement,a
is read only once,b
is read twice but both reads return the same value, and botha
andb
is written only once. It is ok.When you add the third assignment to the left, it becomes a problem:
Now,
a
is read twice, once on operation 1 and once on operation 3, and also written on operation 1 and operation 3. What value shoulda
return on operation 3, the original value or the value after operation 1 is processed?The clever programmer may think that operation 1 is completely executed before operation 3 is processed, but this is not defined by the standard. It just happens to work with most compilers. On operation 3, the compiler may very well return the same value for
a
as it is returned for operation 1, causing the wrong result. This is undefined behavior.