【问题标题】:Does this trick always work? [duplicate]这个技巧总是有效吗? [复制]
【发布时间】:2013-07-18 21:49:48
【问题描述】:

可能重复:
Potential Problem in “Swapping values of two variables without using a third variable”

我最近在一个社区中读到,我们可以使用 XOR 技巧轻松交换两个数字,而无需使用第三个。

m^=n^=m^=n;提到了技巧。

你们怎么看?这个技巧总是有用的吗?

【问题讨论】:

标签: c++ c


【解决方案1】:

你写它的方式,它是未定义的行为。这是因为您在同一序列点中多次修改变量。但是,如果您将其重写如下:

m ^= n;
n ^= m;
m ^= n;

那么就安全了。然而,“有用”是另一个问题,它很少“有用”,有时它实际上比实际使用临时要慢!

您还需要注意别名(指针/引用),因为如果您尝试与自身交换某些内容,那么您最终会意外地将您的值归零。例如:

#define SWAP(m, n) { m ^= n; n ^= m; m ^= n; }

int x[] = { 1, 2, 3, 4 };
int i = 0;
int j = 0;
SWAP(x[i], x[j]); // whoops, x[0] == 0 now, not 1!

更传统的交换实现没有这个问题。

【讨论】:

    【解决方案2】:

    不,它在 C 和 C++ 中都是未定义的行为。它有时可能会起作用,但您不应该依赖它。

    即使是“固定”的变体也并不总是有效:

    m ^= n;
    n ^= m;
    m ^= n;
    

    如果 m 和 n 是对同一个变量的引用,这将失败。在这种情况下,它将值设置为零。

    C 没有引用,但即使在 C 中,如果你尝试使用这个技巧,仍然会潜伏着危险:

    • 您可以尝试将“工作”版本放入宏 SWAP,但如果使用 SWAP(x, x) 调用,将 x 始终设置为零,则可能会失败。
    • 您可以尝试将技巧扩展为交换数组中的两个值,但如果您使用相同的索引,这同样会失败:

      a[m] ^= a[n];
      a[n] ^= a[m];
      a[m] ^= a[n];
      

    现在如果 m == n 再次设置 a[m] 的值为零。

    请不要使用这样的“聪明”技巧。使用临时变量交换两个值。

    【讨论】:

      【解决方案3】:

      使用这个技巧,您可以节省一个额外的内存位置来保存一个临时值。 它可能对整数很有效,但是可读吗?您的上一代优化器可能会这样做。

      【讨论】:

      • 现代 CPU 的临时性能更好。它们可以并行执行这两个分配,但它们必须为 XOR 版本停止。
      • @GMan:你的意思是指令配对?但在这种情况下,哪些作业可以配对?
      • @Nick:与int temp = x; x = y; y = temp;,后两者。
      • @GMan:y 不会在两条指令之间添加依赖关系吗?因此,由于写入后读取而没有配对。这同样适用于前 2 条指令,除非我遗漏了什么:)
      • @GMan:是的,最后两个可以配对:) 我猜mov x, y; 是一个错字。应该是mov x reg1;
      【解决方案4】:

      这通常更危险(在您的情况下,它实际上是未定义的行为;加上如果一个数字为零,就会出错)。除非您的内存非常低,否则最好只使用临时变量(或 stl 交换函数)。这更清楚您在做什么,也更易于维护。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-17
        • 2012-08-11
        • 2015-09-24
        • 2013-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多