首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么i^=j^=i^=j不等于*i^=*j^=*i^=*j

为什么i^=j^=i^=j不等于*i^=*j^=*i^=*j
EN

Stack Overflow用户
提问于 2012-09-08 14:16:15
回答 3查看 348关注 0票数 4

在C中,当变量(假设两者都是int) i小于j时,我们可以使用下面的公式

代码语言:javascript
复制
i^=j^=i^=j

以交换这两个变量的值。例如,让int i = 3j = 5;在计算i^=j^=i^=j之后,我有i = 5j = 3

但是,如果我使用两个int指针来重新使用*i^=*j^=*i^=*j (使用上面的示例),那么我所拥有的将是i = 0j = 3

In C

1

代码语言:javascript
复制
    int i=3, j=5;
    i^=j^=i^=j; // after this i = 5, j=3

2

代码语言:javascript
复制
    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

JavaScript的结果使我更感兴趣

我的示例代码,在ubuntu服务器11.0和gcc上

代码语言:javascript
复制
    #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);
    }

C中未定义的行为

C中未定义的行为是否是导致这一问题的真正原因?

1

在windows 7上使用visual 2005编译的代码会产生预期的结果(输出i= 7,j=9两次)。

2

使用gcc编译的代码在ubuntu ( gcc test.c )上产生意外结果(输出i= 7,j=9,i= 0,j=9)

3.

使用gcc编译的代码在ubuntu ( gcc -O test.c )上产生预期结果(输出i= 7,j=9两次)。)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-09-08 16:25:13

i^=j^=i^=j是C中未定义的行为。

您违反了序列点规则,在两个序列点之间修改了两次i

这意味着实现可以自由地分配任何值,甚至使程序崩溃。

出于同样的原因,*i^=*j^=*i^=*j也是未定义的行为。

(C99,6.5p2)“在前一个序列点和下一个序列点之间,对象最多应该通过表达式的计算修改其存储值一次。

票数 8
EN

Stack Overflow用户

发布于 2012-09-08 14:18:45

考虑以下代码:

代码语言:javascript
复制
 #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;
    }

如果您试图编译它,您将看到第一行的warning: unsequenced modification。就像@ouath说的那样,它的定义不明确。根据C11标准,赋值表达式以读-修改-写的方式工作。这个操作并不是所有CPU体系结构上的原子操作。您可以阅读有关警告这里的更多信息。

有趣的是,对于*pi^=*pj^=*pi^=*pj;,我的LLVM编译器中没有警告。

票数 4
EN

Stack Overflow用户

发布于 2012-09-08 20:23:00

至于Javascript结果中添加的“更有趣的”方面:

虽然表达式在C 正如奥赫在回答中所解释的中没有定义,但在Javascript中定义得很好。然而,在Javascript中如何计算表达式的规则可能不是您所期望的。

ECMAscript规范指出,复合赋值操作符的计算方式如下(ECMA-262 11.13.2):

production : LeftHandSideExpression @= AssignmentExpression,其中@表示上述操作之一,评估如下:

  1. 评价LeftHandSideExpression。
  2. 调用GetValue(结果(1))。
  3. 评价AssignmentExpression。
  4. 调用GetValue(结果(3))。
  5. 将运算符@应用于结果(2)和结果(4)。
  6. 调用PutValue(结果1,结果5)。
  7. 返回结果(5)。

因此,表达式i ^= j ^= i ^= j将按以下步骤进行计算:

代码语言:javascript
复制
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

避免使用xor操作来交换值的另一个原因。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12331518

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档