[英]why i^=j^=i^=j isn't equal to *i^=*j^=*i^=*j
In C, when there are variables (assume both as int
) i
less than j
, we can use the equation 在C中,当有变量(假设两者都是
int
) i
小于j
,我们可以使用等式
i^=j^=i^=j
to exchange the value of the two variables. 交换两个变量的值。 For example, let
int i = 3
, j = 5
; 例如,let
int i = 3
, j = 5
; after computed i^=j^=i^=j
, I have i = 5
, j = 3
. 在计算
i^=j^=i^=j
,我有i = 5
, j = 3
。
However, if I use two int pointers to re-do this, with *i^=*j^=*i^=*j
, using the example above, what I have will be i = 0
and j = 3
. 但是,如果我使用两个int指针重新执行此操作,使用上面的示例,使用
*i^=*j^=*i^=*j
,我所拥有的将是i = 0
和j = 3
。
int i=3, j=5; i^=j^=i^=j; // after this i = 5, j=3
int i = 3, j= 5; int *pi = &i, *pj = &j; *pi^=*pj^=*pi^=*pj; // after this, $pi = 0, *pj = 5
In JavaScript 在JavaScript中
var i=3, j=5; i^=j^=i^=j; // after this, i = 0, j= 3
the result in JavaScript makes this more interesting to me JavaScript中的结果使我对此更感兴趣
my sample code , on ubuntu server 11.0 & gcc 我的示例代码,在ubuntu服务器11.0和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); }
Will the undefined behavior in c be the real reason leads to this question? c中未定义的行为是导致这个问题的真正原因吗?
code compiled use visual studio 2005 on windows 7 produce the expected result ( Output i = 7, j = 9 twice.) 代码编译使用Visual Studio 2005在Windows 7上产生预期的结果(输出i = 7,j = 9两次。)
code compiled use gcc on ubuntu ( gcc test.c ) produce the unexpected result ( Output i = 7, j = 9 then i = 0, j = 9 ) 代码编译在ubuntu ( gcc test.c ) 上使用gcc产生意外结果(输出i = 7,j = 9然后i = 0,j = 9)
code compiled use gcc on ubuntu ( gcc -O test.c ) produce the expected result ( Output i = 7,j = 9 twice. ) 代码编译使用uccntu上的gcc ( gcc -O test.c )产生预期的结果(输出i = 7,j = 9两次。)
i^=j^=i^=j
is undefined behavior in C. i^=j^=i^=j
是C中的未定义行为。
You are violating sequence points rules by modifying i
two times between two sequence points. 您通过在两个序列点之间修改
i
两次来违反序列点规则。
It means the implementation is free to assign any value or even make your program crash. 这意味着实现可以自由分配任何值,甚至使程序崩溃。
For the same reason, *i^=*j^=*i^=*j
is also undefined behavior. 出于同样的原因,
*i^=*j^=*i^=*j
也是未定义的行为。
(C99, 6.5p2) "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression."
(C99,6.5p2)“在前一个和下一个序列点之间,一个对象的存储值最多只能通过表达式的评估来修改一次。”
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=%d j=%d\n", i, j);
i=7, j=9;
*pi^=*pj^=*pi^=*pj;
printf("i=%d j=%d\n", *pi, *pj);
return 0;
}
If you try to compile it you will see a warning: unsequenced modification
for the first line. 如果您尝试编译它,您将看到一个
warning: unsequenced modification
第一行的warning: unsequenced modification
。 As @ouath said it's not well-defined. 正如@ouath所说,它没有明确定义。 According to the C11 Standard the assignment-expressions work in a read-modify-write fashion.
根据C11标准 ,赋值表达式以读 - 修改 - 写方式工作。 This operation isn't atomic on all the CPU architectures.
此操作在所有CPU体系结构上都不是原子操作。 You can read more about the warning here .
您可以在此处阅读有关警告的更多信息。
It's interesting to see that for *pi^=*pj^=*pi^=*pj;
有趣的是,对于
*pi^=*pj^=*pi^=*pj;
there is no warning in my LLVM compiler. 我的LLVM编译器中没有警告。
As for the 'more interesting' aspect added by the Javascript result: 至于Javascript结果添加的“更有趣”方面:
While the expression is undefined in C as explained in ouah's answer , it is well-defined in Javascript. 虽然在ouah的答案中解释了C中的表达式未定义,但它在Javascript中定义良好。 However the rules for how the expression is evaluated in Javascript might not be what you expect.
但是,如何在Javascript中评估表达式的规则可能不是您所期望的。
The ECMAscript spec says that a compound assignment operator is evaluated like so (ECMA-262 11.13.2): ECMAscript规范说复合赋值运算符的评估如下(ECMA-262 11.13.2):
The production AssignmentExpression : LeftHandSideExpression
@=
AssignmentExpression,where@
represents one of the operators indicated above, is evaluated as follows:生产AssignmentExpression:LeftHandSideExpression
@=
AssignmentExpression,其中@
代表上面指出的一个运算符,评估如下:
- Evaluate LeftHandSideExpression.
评估LeftHandSideExpression。
- Call GetValue(Result(1)).
调用GetValue(Result(1))。
- Evaluate AssignmentExpression.
评估AssignmentExpression。
- Call GetValue(Result(3)).
调用GetValue(Result(3))。
- Apply operator @ to Result(2) and Result(4).
将operator @应用于Result(2)和Result(4)。
- Call PutValue(Result(1), Result(5)).
调用PutValue(结果(1),结果(5))。
- Return Result(5).
返回结果(5)。
So the expression i ^= j ^= i ^= j
would be evaluated in the following steps: 因此,表达式
i ^= j ^= i ^= j
将在以下步骤中进行评估:
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
Yet another reason to avoid the trick of using an xor operation to swap values. 避免使用xor操作交换值的技巧的另一个原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.