交换两个整数而不会产生第三次溢出

时间:2019-01-17 18:40:41

标签: c swap

我试图在不使用C的tmp的情况下编写交换功能,这就是我正在使用的内容:

void swap(int *a, int* b) {
    *a += *b;
    *b = *a - *b;
    *a -= *b;
}

现在有一个问题(或者我认为是),如果*a + * b > INT_MAX可能会溢出。令人困惑的是,即使在边缘情况下,它实际上也可以正常工作。有人可以解释为什么吗?

以下是我使用的一些测试用例:

int main() {
    int t1Swap[] = {INT_MAX, 1};
    int t2Swap[] = {INT_MAX, INT_MIN};
    int t3Swap[] = {INT_MAX, INT_MAX-1000};
    int t4Swap[] = {INT_MIN, INT_MIN+1000};
}

谢谢!

4 个答案:

答案 0 :(得分:5)

带符号整数溢出是未定义的行为,因此它可能会起作用,也可能不会起作用,这取决于您的特定系统和编译器。为避免这种未定义的行为,请使用按位XOR运算符而不是加减运算符来交换变量,而无需引入temp

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

答案 1 :(得分:2)

您可以像这样使用XOR;

void swap(int *a, int *b)
{
    if (*a != *b)
    {
        *a^=*b;
        *b^=*a;
        *a^=*b;
    }
}

答案 2 :(得分:2)

即使整数溢出在技术上是未定义的行为,但通常会回绕到INT_MIN。在这种情况下,您的算术实现可以工作(但不能移植)。

答案 3 :(得分:2)

如果您的目标是生成尽可能快的代码(或节省一些内存),那么棘手的XOR或add方法不是最佳选择:

考虑:

void swap1(int *a, int *b)
{
    *a=*a^*b;
    *b=*a^*b;
    *a=*a^*b;
}

void swap2(int *a, int *b)
{
    int c = *a;
    *a = *b;
    *b = c;
}

及其结果代码: X86

swap1:
        mov     eax, DWORD PTR [rdi]
        xor     eax, DWORD PTR [rsi]
        mov     DWORD PTR [rdi], eax
        xor     eax, DWORD PTR [rsi]
        mov     DWORD PTR [rsi], eax
        xor     DWORD PTR [rdi], eax
        ret
swap2:
        mov     eax, DWORD PTR [rdi]
        mov     edx, DWORD PTR [rsi]
        mov     DWORD PTR [rdi], edx
        mov     DWORD PTR [rsi], eax
        ret

因此,没有temp变量,您不会节省任何内存,但是会使算法变慢。有什么意义?