我找到了以下代码段:
#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;
答案 0 :(得分:6)
此算法不起作用,因为它在此行上调用未定义的行为:
x=x+y-(y=x);
^ ^
您正在修改y
,并根据C99标准草案的6.5
部分在同一序列点中使用其值:
在前一个和下一个序列点之间,一个对象应该具有它 通过评估一次最多修改一次的储值 表达式.72)此外,先验值只能读取 确定要存储的值.73)
由于未明确说明子表达式的评估顺序,因此还存在未指明行为的问题:
运算符和操作数的分组由语法表示.74) 除非后面指定(对于函数调用(),&amp;&amp;,||,?:和 逗号运算符),子表达式的评估顺序和 发生副作用的顺序都是未指明的。
在这种情况下,如果您使用clang
,则会提供以下警告:
warning: unsequenced modification and access to 'y' [-Wunsequenced]
x=x+y-(y=x);
~ ^
默认情况下,我可以告诉你。您可以使用gcc
从-Wall
收到类似的警告。
有几个SO问题涉及如何在没有临时的情况下进行交换,例如Swapping two variable value without using 3rd variable。
答案 1 :(得分:2)
这实际上是未定义行为的结果,因为有一些叫做序列点的东西。基本上,在这种情况下,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
,因此x
现为10。现在,y
和y = x
都是10,原始值15现在已丢失。
编辑:至于如何交换的方式,可能是由于优化:
y
,但不要将值存储在y
中。 x = x + y - 10
然后仍然保持值15,而赋值表达式的计算结果为10. x = 10 + 15 - 10
评估为{{1}},产生正确的值。两种情况都有效,但会产生不同的结果。
答案 2 :(得分:2)
我认为括号会先执行......
这是一个无效的假设。括号会影响表达式中运算符的优先级。它们没有指定执行顺序。在
a = b + c + (d * e);
很可能b + c
在(d * e)
之前计算出来。或者它可能不会。 C语言标准保留了子表达式未指定的评估顺序。您发布的代码会调用未定义的行为,因为y
在没有插入序列点的情况下被读取和写入。再次注意,括号不会引入序列点(分号可以)。