0

我找到了以下代码片段:

#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;
}

它实际上交换了变量

谁能解释一下代码如何交换变量?

我认为括号会先执行,然后表达式导致

x=x+y-y;
4

3 回答 3

6

此算法不起作用,因为它在此行调用未定义的行为:

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

根据草案 C99 标准的部分,您正在修改y并在同一序列点内使用其值:6.5

在前一个序列点和下一个序列点之间,对象的存储值最多只能通过表达式的评估修改一次。72)此外,应只读先前值以确定要存储的值。73)

由于未指定子表达式的评估顺序,因此还有未指定行为的问题:

运算符和操作数的分组由语法指示。74) 除稍后指定(对于函数调用 ()、&&、||、?: 和逗号运算符)外,子表达式的求值顺序和中的顺序发生哪些副作用都未指定。

在这种情况下,如果您使用clang它会提供以下警告:

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

据我所知,默认情况下。gcc您可以使用收到类似的警告-Wall

有几个 SO 问题涵盖了如何在没有临时变量的情况下进行交换,例如Swaping two variable value without using 3rd variable

于 2014-07-17T20:22:03.860 回答
2

这实际上是未定义行为的结果,由于称为序列点的东西。基本上,在这种情况下,C 标准不要求在计算表达式期间以任何顺序存储值。事实上,以下情况当然是可能的:

  1. 评估y = x并将值存储在 中y。在这种情况下,x仍然是 10,y现在也是 10。表达式本身的计算结果为 10(赋值的左侧)。
  2. 评估x = x + y - (y = x),相当于x = x + y - 10x并且y都是 10,所以这是x = 10 + 10 - 10x现在是 10。

现在,xandy都是 10,而原来的 15 现在已经丢失了。

编辑:就它如何交换而言,这可能是由于优化:

  1. 评估y = x,但不要将值存储在其中yy然后仍然保持值 15,而赋值表达式的计算结果为 10。
  2. 现在,x = x + y - 10计算为x = 10 + 15 - 10,产生正确的值。

这两种情况都是有效的,但会产生不同的结果。

于 2014-07-17T20:25:06.483 回答
2

我以为括号会先执行...

这是一个无效的假设。括号影响表达式中运算符的优先级。他们没有指定执行顺序。在

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

很可能b + c是之前计算的(d * e)。或者它可能不会。C 语言标准未指定子表达式的求值顺序。由于在没有中间序列点的情况下被读取和写入,您发布的代码会调用未定义的行为。y再次注意括号不会引入序列点(分号会)。

于 2014-07-17T20:25:31.913 回答