我找到了以下代码片段:
#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;
我找到了以下代码片段:
#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;
此算法不起作用,因为它在此行调用未定义的行为:
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。
这实际上是未定义行为的结果,由于称为序列点的东西。基本上,在这种情况下,C 标准不要求在计算表达式期间以任何顺序存储值。事实上,以下情况当然是可能的:
y = x
并将值存储在 中y
。在这种情况下,x
仍然是 10,y
现在也是 10。表达式本身的计算结果为 10(赋值的左侧)。x = x + y - (y = x)
,相当于x = x + y - 10
。x
并且y
都是 10,所以这是x = 10 + 10 - 10
,x
现在是 10。现在,x
andy
都是 10,而原来的 15 现在已经丢失了。
编辑:就它如何交换而言,这可能是由于优化:
y = x
,但不要将值存储在其中y
。y
然后仍然保持值 15,而赋值表达式的计算结果为 10。x = x + y - 10
计算为x = 10 + 15 - 10
,产生正确的值。这两种情况都是有效的,但会产生不同的结果。
我以为括号会先执行...
这是一个无效的假设。括号影响表达式中运算符的优先级。他们没有指定执行顺序。在
a = b + c + (d * e);
很可能b + c
是之前计算的(d * e)
。或者它可能不会。C 语言标准未指定子表达式的求值顺序。由于在没有中间序列点的情况下被读取和写入,您发布的代码会调用未定义的行为。y
再次注意括号不会引入序列点(分号会)。