使用C++中的这个表达式 x = y - x + (y = x) 的奥秘

3
在Python中,你可以使用如下表达式轻松交换两个变量的值:
x, y = y, x

相比之下,在C++中,如果你想交换两个变量的值,通常会使用一个临时变量来存储其中一个变量的值,就像这样:

int var1 = 100;
int var2 = 200;

int temp = var1;
var1 = var2;
var2 = temp;

这很简单,但你需要写很多代码。

我一直在跟随一位讲授C++课程的教授,他发现了一种新的紧凑方式,在魔术般的方式下交换2个变量的值:

int x = 200;
int y = 100;

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

这似乎令人难以置信,但它可以在他使用的编译器和我的 Apple LLVM version 6.0 (clang-600.0.56) 中都工作。

看起来表达式被解释为以下内容:

  1. (y = x) // 返回x的值
  2. -x + x = 0
  3. x = y + 0
  4. x = y
  5. y = x //最终,y接收到x的初始值

如果我尝试在循环中交换一些变量的值,它似乎也可以工作:

for (int i = -10; i <= 10; i++) {
    for (int j = 10; j >= -10; j--) {
        int x = i, y = j;
        x = y - x + (y = x);

        std::cout << "x = " << x << "\ny = " << y << '\n';
    }
}

我们已经看到了变量交换的过程,但是我的编译器给出了以下警告:

main.cpp:28:22: 警告:对'y'进行了未排序的修改和访问[-Wunsequenced]

如果有警告,我认为这不是C++中交换两个变量值的新标准方式,而只是这位教授巧妙的解决方法。
为什么这种方法没有被C++标准化,它为什么能够正常工作?

1
请参考以下链接了解有关程序设计的相关知识:http://en.wikipedia.org/wiki/Sequence_point - Fredrik Pihl
10
std::swap()也很简洁。 - stefaanv
3个回答

10
这是未定义的行为,不能保证可行。表达式中参数的计算顺序没有规定。因此,在进行y = x赋值之前或之后访问y的值都是允许的。
这样指定的原因是为了允许优化的灵活性。

6

“它”能够正常运行只是因为你很不幸。

是的,我说的是不幸。这段代码存在未定义行为;它看起来“正常”只是因为编译器让你得以运行可能在下一次运行时出现问题的代码。

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

对象y被访问了两次,一次读取其值,一次赋值。语言不定义这些访问发生的顺序 - 或者它们以任何顺序发生。如警告消息所述,它们是“未排序”的。可能的行为不仅限于两个可能的顺序; 行为完全未定义。

此外,加法和/或减法可能会溢出,这是另一个潜在的未定义行为源。


3
没有未能诊断问题,它打印了一个警告。 - Barmar
@Barmar:好观点,我已相应更新了我的答案。 - Keith Thompson

2

这个表达式 `x = y - x + (y = x);` 在C语言中是未定义行为,C99规范列出的一种未定义行为是:

在两个序列点之间,一个对象被多次修改,或者被修改并且先前的值被读取,而不是为了确定要存储的值

这个表达式中唯一的序列点是表达式的开始和完整表达式的结束。


真的,但问题标记为C++。 :D - Jonathan Leffler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接