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