Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 分析在没有第三个临时变量的情况下交换两个变量的“技术”_C_Assembly - Fatal编程技术网

C 分析在没有第三个临时变量的情况下交换两个变量的“技术”

C 分析在没有第三个临时变量的情况下交换两个变量的“技术”,c,assembly,C,Assembly,我遇到了一种在没有第三个临时变量的情况下交换两个变量int、char或指针的技术,如下所示: int a = Something ; int b = SomethingElse ; a ^= b ; b ^= a ; a ^= b ; 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 通常的做法是: in

我遇到了一种在没有第三个临时变量的情况下交换两个变量int、char或指针的技术,如下所示:

int a = Something ;  
int b = SomethingElse ;  
a ^= b ;  
b ^= a ;  
a ^= b ;
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
通常的做法是:

int a = Something ;  
int b = SomethingElse ;  
int temp = a ;  
a = b ;  
b = temp ;
所有这些都很好,但是分享这项技术的人通常会说它没有使用额外的空间

A没有多余的空间是真的吗?我认为,与内存到内存的异或操作相比,内存到内存的复制需要更少的指令机器代码

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)**
这项技术似乎会导致更长的代码和更长的运行时间

B技术在某些方面或某些情况下更快或更好

看起来这项技术速度较慢,占用更多内存,而且不太适合浮点运算

编辑: 似乎可能存在一些潜在的重复:

但这个问题显然不同: A该问题因不具建设性而被关闭,可能会引发辩论、争论、投票或广泛讨论,而该问题是在寻找事实参考,如是否真实这样更好吗?
B这个问题是关于为什么人们不使用这项技术,而这个问题是关于对这项技术的分析,而不考虑人们为什么使用或不使用它。

没有明确的答案:它太依赖于:

机器的架构、处理器数量、内存缓存大小等;和 编译器优化的质量。 如果所有操作都在寄存器内执行,则与复制相比,不太可能有XOR的性能损失

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

register int temp;
异或技术或加减法的使用,如在a-=b中;b+=a;a=b-a;可以追溯到内存是关键资源的时候,保存堆栈条目可能非常重要。如今,这种方法的唯一价值就是代码混淆


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

没有明确的答案:这太依赖于:

机器的架构、处理器数量、内存缓存大小等;和 编译器优化的质量。 如果所有操作都在寄存器内执行,则与复制相比,不太可能有XOR的性能损失

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

register int temp;
异或技术或加减法的使用,如在a-=b中;b+=a;a=b-a;可以追溯到内存是关键资源的时候,保存堆栈条目可能非常重要。如今,这种方法的唯一价值就是代码混淆


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

如果您操作的是整数或双精度数或更一般的值,任何包含加法和减法运算符的类型,您都可以这样做:

int a = Something ;  
int b = SomethingElse ;  
a ^= b ;  
b ^= a ;  
a ^= b ;
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

如果要处理整数、双精度或更一般的任何包含加减运算符的类型,可以这样做:

int a = Something ;  
int b = SomethingElse ;  
a ^= b ;  
b ^= a ;  
a ^= b ;
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

对于较低级别,例如组件变量不再具有永久位置。有时一个变量会在内存中,但有时同一个变量会在一个寄存器中,有时在不同的寄存器中

生成代码时,编译器必须跟踪每个变量在每个点上的位置。对于像a=b这样的操作,如果b在register1中,那么编译器只是决定a现在也在register1中。不需要移动或复制任何内容

现在考虑一下:

// 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
如果您仔细想想,就会发现不需要移动或复制数据,也不需要生成代码。现代CPU可以非常快地什么都不做

注意:如果一个变量是堆栈上的局部变量,并且不在寄存器中,那么编译器应该能够进行相同的重命名,以避免移动任何内容。如果变量是全局变量,则情况会变得更复杂-很可能导致每个全局变量的内存加载和内存存储,例如,如果两个变量都是全局变量,则两个加载和两个存储

对于异或和加法/减法,编译器可能能够对其进行优化,使其成为零;但我不会指望的。临时变量变动更有可能得到很好的优化

当然,并不是所有的东西都小到可以放入一个寄存器。例如,可能您正在交换结构,每个结构有1234字节。在这种情况下,程序员可能使用memcpy,而编译器必须进行复制;或者程序员可以使用XOR或加法/减法一次执行一个字段,而编译器必须这样做。
对于这些,memcpy更有可能得到更好的优化。然而,程序员可能更聪明,不交换1234字节的数据,只交换指向数据的指针。指针即使在它们指向的数据不存在时也可以装入寄存器,因此可能不会为此生成代码。

对于较低级别,例如,程序集变量不再具有永久位置。有时一个变量会在内存中,但有时同一个变量会在一个寄存器中,有时在不同的寄存器中

生成代码时,编译器必须跟踪每个变量在每个点上的位置。对于像a=b这样的操作,如果b在register1中,那么编译器只是决定a现在也在register1中。不需要移动或复制任何内容

现在考虑一下:

// 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
如果您仔细想想,就会发现不需要移动或复制数据,也不需要生成代码。现代CPU可以非常快地什么都不做

注意:如果一个变量是堆栈上的局部变量,并且不在寄存器中,那么编译器应该能够进行相同的重命名,以避免移动任何内容。如果变量是全局变量,则情况会变得更复杂-很可能导致每个全局变量的内存加载和内存存储,例如,如果两个变量都是全局变量,则两个加载和两个存储

对于异或和加法/减法,编译器可能能够对其进行优化,使其成为零;但我不会指望的。临时变量变动更有可能得到很好的优化


当然,并不是所有的东西都小到可以放入一个寄存器。例如,可能您正在交换结构,每个结构有1234字节。在这种情况下,程序员可能使用memcpy,而编译器必须进行复制;或者程序员可以使用XOR或加法/减法一次执行一个字段,而编译器必须这样做。对于这些,memcpy更有可能得到更好的优化。然而,程序员可能更聪明,不交换1234字节的数据,只交换指向数据的指针。即使指针指向的数据不在寄存器中,指针也可以装入寄存器,因此可能不会为此生成任何代码。

@Prem之所以这样做,是因为您还没有阅读“如何提问”,这样您就知道这不属于超级用户。堆栈溢出!=实际上,异或交换通常没有意义,在机器代码中,临时变量通常只是一个寄存器,所以它基本上是免费的。此外,大多数体系结构不能在内存上执行异或操作,并且无论如何都必须将至少一个操作数加载到寄存器中。如果两者都已经在寄存器中,交换基本上是一个不操作,只不过编译器重新分配寄存器,总之,这取决于CPU架构和编译器优化。通过编译器运行这两个变体,并比较输出。这基本上就是我们所能说的。至于代码的清晰性,我更喜欢在更无用的求职者中流行的临时的、实际上是无用的技巧。根据编译器的说法,应该优化你的代码,这样XOR就不会有任何改进。并展示了如何使用指针交换任何类型的变量。@Prem它们这样做是因为您还没有阅读“如何提问”,这样您就知道这不属于超级用户。堆栈溢出!=实际上,异或交换通常没有意义,在机器代码中,临时变量通常只是一个寄存器,所以它基本上是免费的。此外,大多数体系结构不能在内存上执行异或操作,并且无论如何都必须将至少一个操作数加载到寄存器中。如果两个寄存器都已经在寄存器中,那么交换基本上是不可操作的,只是编译器重新分配寄存器。总之,它取决于CPU体系结构和编译器优化。通过编译器运行这两个变体,并比较输出。这基本上就是我们所能说的。至于代码的清晰性,我更喜欢在更无用的求职者中流行的临时的、实际上是无用的技巧。根据编译器的说法,应该优化你的代码,这样XOR就不会有任何改进。并展示了如何使用指针来交换任何类型的变量。但实际上对于双数并不适用,考虑NaN或A++INF,B= -INF,或者A= 1E300,B=1。XOR为双工工作,在语言中,让你用SSE内联做C。@哈罗德:好的观察对INT不起作用,因为在A+B中可能发生的溢出是未定义的行为。但是对于双打实际上不起作用,考虑Na或A++INF,B= -INF,或者A= 1E300,B=1。XOR适用于double,例如,在允许您使用SSE intrinsic实现C的语言中。@harold:好的Observations不适用于int,因为在a+=b上可能发生的溢出是未定义的行为。