C++的魔术,这个表达式 x = y - x + (y = x)
Magic in C++ with this expression x = y - x + (y = x)
在 Python 中,您可以使用如下表达式轻松交换 2 个变量的值:
x, y = y, x
另一方面,在C++中,如果要交换 2 个变量的值,通常使用临时变量来存储其中一个变量的值,如下所示:
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)
。
似乎表达式的解释方式如下:
- (y = x)//返回 x 的值
- -x + x = 0
- x = y + 0
- x = y
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';
}
}
我们已经看到交换已经完成,但我的编译器给了我这个警告:
主.cpp:28:22: 警告:未排序的修改和访问"Y" [-温序列]
如果有警告,我想这不是交换 2 个变量值的新标准方法,而只是这位教授的一个巧妙的解决方法。
为什么这种方法在C++中没有标准化,为什么它到底有效?
这是未定义的行为,不能保证有效。未指定表达式中参数的计算顺序。因此,允许在执行y = x
分配之前或之后访问减法的y
值。
这样指定它的原因是允许优化的灵活性。
它"有效"是因为你运气不好。
是的,我说倒霉。代码具有未定义的行为;它似乎"工作"的事实意味着您的编译器可以让您摆脱下次运行它时可能失败的代码。
x = y - x + (y = x);
对象y
被访问两次,一次读取其值,一次为其赋值。该语言没有定义这些访问发生的顺序 - 或者根本不以任何顺序发生。正如警告消息所说,它们是"未排序的"。可能的行为不限于两个可能的订单;行为是完全未定义的。
此外,加法和/或减法可能会溢出,这是未定义行为的另一个潜在来源。
- x + (y = x);, 是 C 语言中未定义的行为 - C99 规范列出的一种未定义行为是:
在两个序列点之间,一个对象被多次修改,或者 被修改并读取先前的值,而不是确定 要存储的值
此表达式中唯一的序列点是表达式的开头和完整表达式的结尾。
- (C++)分析树以计算返回错误值的简单算术表达式
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 提升精神:解析布尔表达式并简化为规范范式
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 使用正则表达式regex_search在字符串中查找字符串
- 如何确认我的constexpr表达式实际上已经在编译时执行
- 概念中的cv限定符需要表达式参数列表
- 为什么constexpr的性能比正常表达式差
- 对于结构,表达式必须是可修改的ivalue
- 当一个值是非常量但用常量表达式初始化时使用constexpr
- 将fold表达式与std::一起用于两个元组
- 断言中的Fold表达式在某些计算机上编译,但在其他计算机上不编译
- 标记 '","' 之前的预期主表达式
- gcc和clang在表达式是否为常量求值的问题上存在分歧
- 如何计算具有指定类型的表达式的相对精度和绝对精度
- 带有用户定义类的c++折叠表达式
- 即使使用调试编译标志,表达式也是"optimized out"
- holeMenuProgram.cpp:38:1 错误:'}'令牌之前的预期主表达式
- 在 C++ 中使用正则表达式错误时出现问题 括号表达式中的范围无效
- C++的魔术,这个表达式 x = y - x + (y = x)