- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
void swap(int* a, int* b) {
if (a != b)
*a ^= *b ^= *a ^= *b;
}
因为上面的 *a ^= *b ^= *a ^= *b
只是 *a = *a ^ (*b = *b ^ (* a = *a ^ *b))
,可以(例如)在第三个 *a
之前对第二个 *a
进行求值(对于 XOR)修改(由=)?
用 C99/C11/C++98/C++11 写有关系吗?
最佳答案
C++11 标准说:
5.17/1: The assignment operator (=) and the compound assignment operators all group right-to-left. (...) the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.
1.9/15: If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.
所以 *a ^= *b
的顺序如下:
*a
和*b
被计算。它NOT确定在哪个订单*a
(*a ^= *b)
现在 *b ^= *a ^= *b
,根据优先级规则是 *b ^= (*a ^= *b)
:
*b
和(*a ^= *b)
是计算出来的。它NOT 确定的顺序。但是因为 *b
没有被 (*a ^= *b)
修改,所以没关系。*b
但是现在根据优先级规则 *a ^
: *a ^= *b ^= *a ^= *b
进行未指定排序 = (*b ^= (*a ^= *b) )
*a
和(*b ^= (*a ^= *b) )
被计算。它NOT 确定的顺序。但是因为 *a
是由 (*b ^= (*a ^= *b) )
修改的。所以结果将取决于首先计算哪个值。这显然是一个 U.B. 假设 *a
首先被评估,(即在任何其他事情之前):
你会得到它的原始值,它将与 (*b ^= (*a ^= *b) )
的值进行异或,即原始 *b
与原始 *a
再次与 *b
异或。这将导致 0(将存储在 *a
中)。
假设(*b ^= (*a ^= *b) )
先被计算,那么它的结果就是原来的*a
,但是*a
的内容改成了原来的*a
与原来的*b
异或。因此,这将导致原始的 *b
(将存储在 *a
中)
顺便说一下,在这两种情况下,*b
都包含 *a
的原始值与 *b
异或两次,这意味着 *b
将包含原始的 *a
。
结论:这里证明了 *b
的最终值是由这个表达式唯一确定的,但是 *a
的最终值> 不是唯一定义的(可能有两个值)。所以这显然是一个UNSPECIFIED/UNDEFINED RESULT!它可能会交换,也可能会丢失 *a
,具体取决于您的编译器。
我已经在上面证明了前两个复合赋值是明确指定的。所以我们只需要确保最后一个复合赋值在它之后完成。这可以通过逗号运算符来保证:
5.18/1: A pair of expressions separated by a comma is evaluated left-to-right and the value of the left expression is discarded
因此,以下将起作用:
void safe_swap(int* a, int* b) {
if (a != b)
*b ^= *a ^= *b, *a ^= *b;
}
在一些没有更多可用内存的嵌入式设备上,在极端条件下可能不得不使用这种高级技巧。但它有缺点。
首先它很难理解,而且如上所示,容易出错。那么它可能不像看起来那样有效。一些依赖于实现的实验 show less optimal code : 3 个 MOV
和 3 个 XOR
,而使用临时变量的经典交换只有 4 个 MOV
。一些informal benchmarks建议大多数时候它可能会慢 3% 到 8%。
顺便说一句,经典的swap也可以写成一条语句:
void modern_swap(int*a, int*b) {
if (a!=b)
tie(*a,*b)=make_pair(*b,*a);
}
关于c++ - XOR 交换算法中运算符的未定义行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28782068/
Or 运算符 对两个表达式进行逻辑“或”运算。 result = expression1 Or expression2 参数 result 任意数值变量。 expression1 任意
Not 运算符 对表达式执行逻辑非运算。 result = Not expression 参数 result 任意数值变量。 expression 任意表达式。 说明 下表显示如何
Is 运算符 比较两个对象引用变量。 result = object1 Is object2 参数 result 任意数值变量。 object1 任意对象名。 object2 任意
\ 运算符 两个数相除并返回以整数形式表示的结果。 result = number1\number2 参数 result 任意数值变量。 number1 任意数值表达式。 numbe
And 运算符 对两个表达式进行逻辑“与”运算。 result = expression1 And expression2 参数 result 任意数值变量。 expression1
运算符(+) 计算两个数之和。 result = expression1 + expression2 参数 result 任意数值变量。 expression1 任意表达式。 exp
我对此感到困惑snippet : var n1 = 5-"4"; var n2 = 5+"4"; alert(n1); alert(n2); 我知道 n1 是 1。那是因为减号运算符会将字符串“4”转
我想我会得到 12,而不是 7。 w++,那么w就是4,也就是100,而w++, w 将是 8,1000;所以 w++|z++ 将是 100|1000 = 1100 将是 12。 我怎么了? int
Xor 运算符 对两个表达式进行逻辑“异或”运算。 result = expression1 Xor expression2 参数 result 任意数值变量。 expression1
Mod 运算符 两个数值相除并返回其余数。 result = number1 Mod number2 参数 result 任意数值变量。 number1 任意数值表达式。 numbe
Imp 运算符 对两个表达式进行逻辑蕴涵运算。 result = expression1 Imp expression2 参数 result 任意数值变量。 expression1 任
Eqv 运算符 执行两个表达式的逻辑等价运算。 result = expression1 Eqv expression2 参数 result 任意数值变量。 expression1 任
我有一个运算符重载的简单数学 vector 类。我想为我的运算符(operator)获取一些计时结果。我可以通过计时以下代码轻松计时我的 +=、-=、*= 和/=: Vector sum; for(s
我是用户定义比较运算符的新手。我正在读一本书,其中提到了以下示例: struct P { int x, y; bool operator、运算符<等),我们
在 SQL 的维基百科页面上,有一些关于 SQL 中 bool 逻辑的真值表。 [1] 维基百科页面似乎来源于 SQL:2003 标准。 等号运算符 (=) 的真值表与 SQL:2003 草案中的 I
我遇到了一个奇怪的 C++ 运算符。 http://www.terralib.org/html/v410/classoracle_1_1occi_1_1_number.html#a0f2780081f
我正在阅读关于 SO 和 answers 中的一个问题,它被提到为: If no unambiguous matching deallocation function can be found, pr
我偶然发现了这个解决方案,但我无法理解其中到底发生了什么。谁能解释一下! 据我了解,它试图通过计算一半的单元格然后将其加倍来计算 a*b 网格中的单元格数量。但是我无法理解递归调用。 请不要建议其他解
Go的基本类型 布尔类型bool 长度:1字节 取值:布尔类型的取值只能是true或者false,不能用数字来表示 整型 通用整型 int / uint(有符号 / 无符号,下面也类似) 长度:根据运
在本教程中,您将学习JavaScript中可用的不同运算符,以及在示例的帮助下如何使用它们。 什么是运算符? 在JavaScript中,运算符是一种特殊符号,用于对运算数(值和变量)执行操作。例如,
我是一名优秀的程序员,十分优秀!