分析一种技术"用于交换2个变量而没有第三个临时变量

时间:2015-07-28 11:40:32

标签: c assembly

我遇到过"技术"用于交换2个变量(整数,字符或指针)没有第三个临时变量,如下所示:

int a = Something ;  
int b = SomethingElse ;  
a ^= b ;  
b ^= a ;  
a ^= b ;

正常方式是:

int a = Something ;  
int b = SomethingElse ;  
int temp = a ;  
a = b ;  
b = temp ;

这一切都很好,但是那些分享这种"技术"通常将其声明为而不使用额外的空间

(A)这是否真的没有多余的空间?我认为,"内存到内存复制"与"内存到内存XOR操作"。

相比,将需要更少的指令(机器代码)
int temp = a <==> move content of memory location a to memory location temp **(1 instruction)**, possibly via a register **(2 instructions)**

a ^= b <==> move contents of memory location a to register1, move contents of memory location b to register2, xor register1 and register2 (store results in register1) , move register1 to memory location a **(about 4 instructions)**

似乎&#34;技术&#34;将导致更长的代码和更长的运行时间。

(B)&#34;技术&#34;以某种方式或某些情况下更快(或更好)?

这似乎是&#34;技术&#34;速度较慢,占用内存较多,而且不适合浮点。

修改
似乎可能存在一些潜在的重复:
Why don't people use xor swaps?

但这个问题明显不同
(A)该问题已被关闭为&#34; Not Constructive&#34; ,它可能会征求辩论,争论,民意调查或扩展讨论,而这个问题正在寻找事实参考,例如&#34;是真的吗?&#34; &安培; &#34;这样更好吗?&#34;
(B)这个问题是为什么不使用&#34;技术&#34;,而这个问题是关于&#34;技术的分析& #34;,没有看到为什么人们使用它或不使用它。

3 个答案:

答案 0 :(得分:3)

没有确定的答案:它过分依赖于:

  1. 机器的体系结构(处理器数量,内存缓存大小等);和
  2. 编译器优化的质量。
  3. 如果所有操作都在寄存器中执行,则与复制相比,XOR不会有性能损失。

    如果你使用第三个变量,你可以通过声明来帮助编译器:

    register int temp;
    

    使用XOR技术(或加法和减法,如a-=b; b+=a; a=b-a;)可以追溯到内存是一个关键资源,保存堆栈条目可能非常重要。这些天,唯一的价值就是代码混淆。

    我完全不知道XOR对浮点值的影响是什么,但我怀疑它们可能首先转换为整数:你需要尝试它,但不能保证所有编译器都会给它同样的结果。

答案 1 :(得分:1)

For lower level (e.g. assembly) "variables" no longer have a permanent location. Sometimes a variable will be in memory, but sometimes the same variable will be in one register, and sometimes in a different register.

When generating code, the compiler has to keep track of where each variable happens to be at each point. For an operation like a = b, if b is in register1 then the compiler just decides that a is now also in register1. Nothing needs to be moved or copied.

Now consider this:

// r0 contains variable a
// r1 contains variable b

    temp = a

// r0 contains variable a and variable temp
// r1 contains variable b

    a = b

// r0 contains variable temp
// r1 contains variable b and variable a

    b = temp

// r0 contains variable temp and variable b
// r1 contains variable a

If you think about this you'll realise that no data needs to be moved or copied, and no code needs to be generated. Modern CPUs are able to do "nothing" extremely quickly.

Note: If a variable is a local variable (on the stack) and isn't in a register, then the compiler should be able to do the same "renaming" to avoid moving anything. If the variable is a global variable then things get more complicated - most likely causing a load from memory and a store to memory for each global variable (e.g. 2 loads and 2 stores if both variables are global).

For XOR (and addition/subtraction) the compiler might be able to optimise it so that it becomes nothing; but I wouldn't count on it. The temporary variable moves are much more likely to be optimised well.

Of course not everything is small enough to fit in a register. For example, maybe you're swapping structures and they're 1234 bytes each. In this case the programmer might use memcpy() and the compiler has to do the copies; or the programmer might do one field at a time with XOR (or addition/subtraction) and the compiler has to do that. For these the memcpy() is much more likely to be better optimised. However, maybe the programmer is smarter, and doesn't swap the 1234 bytes of data and only swaps pointers to the data. Pointers fit in registers (even when the data they point to doesn't), so maybe no code is generated for that.

答案 2 :(得分:0)

如果你正在操纵整数或双精度(或者更一般地说,任何包含加法和减法运算符的类型),你可以这样做:

int a = 5;
int b = 7;
a += b;    // a == 12, b == 7
b = a - b; // a == 12, b == 5
a -= b;    // a == 7,  b == 5