c 中 a+=k 和 a=a+b 不同吗?

Are a+=k and a=a+b different in c?

我尝试在没有模板的情况下进行交换,但遇到了这个问题。 a+=ka=a+b 有区别吗?第一种情况有什么问题?

a += b-(b=a); // this print same value of two a and b.

a = a + b-(b=a); // this thing correctly swapped values.  

来自 C11 standard 6.5.16.2.3

A compound assignment of the form E1 op= E2 is equivalent to the simple assignment expression E1 = E1 op (E2), except that the lvalue E1 is evaluated only once, and with respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation.

已发布代码中的未定义行为

这两个语句都会导致未定义的行为,因此不应期望它们会给出相同的结果。

来自 C11 标准草案 §6.5p2

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

在发布的代码中,(b=a) 是一个计算结果为 a 的表达式,但具有分配值的 副作用 ab。在这两个语句中,(b=a) 的值(即 a 的值)都是从 b 中减去的,但是这里 b 是一个 值计算 导致 b 的值。这两个表达式之间没有sequence point,也就是说值计算b是在(b=a)之前还是之后是不确定的。由于 b 的副作用和 b 的值计算在两个语句中都是未排序的,因此都会导致未定义的行为。

为什么你需要这样写代码?

最好避免 "clever" 这样的代码。在这种情况下,看似聪明的代码具有未定义的行为;在其他情况下,对于必须维护代码的其他人来说,聪明的代码可能只是难以理解,甚至对于你自己来说也是如此。编写易于理解和易于维护的清晰代码。当您遇到性能问题并确定了罪魁祸首时,只需担心优化。编译器很聪明,它们可以识别常见的习惯用法,并且能够在打开优化时为这些常见的习惯用法生成接近最佳的代码。您很少需要逗号运算符或不直观的 XOR 交换;对于简单的交换,这是编程中的常见操作,更喜欢明显的解决方案,让你的编译器完成它的工作。

显而易见的解决方案,使用与 ab 相同类型的临时变量,易于理解,永远不会有未定义的行为(甚至是依赖于实现的行为),并且通常会被一个好的编译器优化为比来自善意的程序员微优化的代码更高性能的代码:

temp = a;
a = b;
b = temp;

两者都会导致未定义的行为,因为您正在访问和修改 b 而没有插入序列点:

6.5p2:

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.

以下是使用 +/- 执行此操作的方法(无 UB 仅适用于无符号数字类型,因为带符号的 +/- 可能会导致未定义的溢出):

a+=b, b=a-b, a=a-b;

或使用 xor(始终无 UB):

a^=b, b^=a, a^=b;

Gcc 和 clang 似乎可以识别这两种模式并通过临时将它们编译为交换,这是常见体系结构上最有效的方法:https://gcc.godbolt.org/z/3W_22r