使用此表达式的C++中的Magic x = y - x +(y = x)

nbr*_*bro 3 c++ variables

在Python中,您可以使用如下表达式轻松地交换2个变量的值:

x, y = y, x
Run Code Online (Sandbox Code Playgroud)

另一方面,在C++中,如果要交换2个变量的值,通常使用临时变量来存储其中一个变量的值,如下所示:

int var1 = 100;
int var2 = 200;

int temp = var1;
var1 = var2;
var2 = temp;
Run Code Online (Sandbox Code Playgroud)

这很简单,但你必须编写很多代码.

我一直关注C++讲座的教授发现了一种新的紧凑方式,以神奇的方式交换2个变量的值:

int x = 200;
int y = 100;

x = y - x + (y = x);
Run Code Online (Sandbox Code Playgroud)

这似乎令人难以置信,但它适用于他正在使用的编译器和我的编译器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';
    }
}
Run Code Online (Sandbox Code Playgroud)

我们已经看到交换完成了,但我的编译器给了我这个警告:

main.cpp:28:22:警告:无序修改和访问'y'[-Wunsequenced]

如果有警告,我想这不是交换2个变量值的新标准方法,而只是这位教授的一个巧妙的解决方法.

为什么这种方法在C++中没有标准化,为什么它的确有效呢?

Bar*_*mar 10

这是未定义的行为,并不保证可以正常工作.未指定表达式中参数的评估顺序.因此,允许y在执行y = x赋值之前或之后访问减法的值.

它被指定的原因是允许优化的灵活性.


Kei*_*son 6

它"有效",因为你不走运.

是的,我说不走运.代码具有未定义的行为; 它似乎"工作"的事实意味着你的编译器让你逃脱下次运行时可能失败的代码.

x = y - x + (y = x);
Run Code Online (Sandbox Code Playgroud)

该对象y被访问两次,一次读取其值,一次为其分配值.该语言没有定义这些访问发生的顺序 - 或者根本不以任何顺序发生.正如警告信息所说,他们"没有经过考验".可能的行为不仅限于两种可能的顺序; 行为完全未定义.

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

  • 它确实没有诊断出来.它打印了一个警告. (3认同)