交换指针值

时间:2017-05-28 04:16:03

标签: c++ c pointers swap

如何在不使用临时变量的情况下交换两个指针的值。通过交换值,我指的是存储在每个指针中的地址。指针可以是任何类型,例如int。这是Qualcomm的采访问题。据我所知,只有指针允许减法,我们不能执行任何其他算术运算。

2 个答案:

答案 0 :(得分:3)

这种简单的方法可以工作,照顾类型转换。在我的机器中,它的指针大小等于long。

#include <stdio.h>
int main()
{
    int *x = malloc(sizeof(int)), *y = malloc(sizeof(int));

    printf("Before Swap x: %p y: %p \n", x, y);

    // if x= 5 & y = 10, 
    // then code to swap 'x' (1010) and 'y' (0101)
    x = (int*)((uintptr_t )x ^ (uintptr_t )y); // x = x ^ y, now x becomes 15 (1111)
    y = (int*)((uintptr_t )x ^ (uintptr_t )y); // y = x ^ y, y becomes 10 (1010)
    x = (int*)((uintptr_t )x ^ (uintptr_t )y); // x = X ^ y, x becomes 5 (0101)

    printf("After Swapping: x = %p, y = %p", x, y);

    return 0;
}

答案 1 :(得分:2)

这是一个适用于amd64(又名x86_64)的解决方案,或任何其他未使用高16位地址的64位系统(代码中未检查此要求!)。

#include <cassert>
#include <cstring>
#include <iostream>

// swap two pointers without using any additional space
// this is really a terrible idea and should never be used
template <typename T>
void ptr_swap(T*& p1, T*& p2)
{
    // this only works on amd64, where the high 16 address bits are unused
    static_assert(sizeof(T*) == 8, "only works on amd64");

// swap Nth pair of bytes
#define PTR_SWAP_PAIR(N) \
    memcpy((char*)&p1 + 6, (char*)&p2 + N, 2); \
    memcpy((char*)&p2 + N, (char*)&p1 + N, 2); \
    memcpy((char*)&p1 + N, (char*)&p1 + 6, 2); \

    PTR_SWAP_PAIR(0);
    PTR_SWAP_PAIR(2);
    PTR_SWAP_PAIR(4);

    // restore amd64 pointer invariant (sign extension)
    p1 = (T*)(((intptr_t)p1 << 16) >> 16);
}

int main()
{
    int a = 1234567890;
    int b = 999777555;
    int* pa = &a;
    int* pb = &b;

    ptr_swap(pa, pb);

    assert(pa == &b);
    assert(pb == &a);

    std::cout << *pa << '\n';
    std::cout << *pb << '\n';
}

关于高16地址位可用作暂存区的参考:Using the extra 16 bits in 64-bit pointers

如果您对为上面生成的汇编代码感到好奇:

    movzx   eax, WORD PTR [rsi]
    mov     WORD PTR [rdi+6], ax
    movzx   eax, WORD PTR [rdi]
    mov     WORD PTR [rsi], ax
    movzx   eax, WORD PTR [rdi+6]
    mov     WORD PTR [rdi], ax
    movzx   eax, WORD PTR [rsi+2]
    mov     WORD PTR [rdi+6], ax
    movzx   eax, WORD PTR [rdi+2]
    mov     WORD PTR [rsi+2], ax
    movzx   eax, WORD PTR [rdi+6]
    mov     WORD PTR [rdi+2], ax
    movzx   eax, WORD PTR [rsi+4]
    mov     WORD PTR [rdi+6], ax
    movzx   eax, WORD PTR [rdi+4]
    mov     WORD PTR [rsi+4], ax
    movzx   eax, WORD PTR [rdi+6]
    mov     WORD PTR [rdi+4], ax
    mov     eax, 16
    shlx    rax, QWORD PTR [rdi], rax
    sar     rax, 16
    mov     QWORD PTR [rdi], rax

使用std::swap()

    mov     rax, QWORD PTR [rdi]
    mov     rdx, QWORD PTR [rsi]
    mov     QWORD PTR [rdi], rdx
    mov     QWORD PTR [rsi], rax

所以是的,可怕的。

编辑:这是由@Ajay回答的汇编:

    mov     rax, QWORD PTR [rdi]
    xor     rax, QWORD PTR [rsi]
    mov     QWORD PTR [rdi], rax
    xor     rax, QWORD PTR [rsi]
    mov     QWORD PTR [rsi], rax
    xor     QWORD PTR [rdi], rax

std::swap()相比,它会花费两个额外的指令并保存一个寄存器(rdx)。