如何在Delphi中有效地交换指针?我试图交换整数类型的指针。以下示例有效,但使用64位编译时,I2
为0。
program Project11;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
procedure Swap(const P1, P2);
asm
{$if defined(CPUX86)}
xchg ecx, [eax]
xchg ecx, [edx]
xchg [eax], ecx
{$else}
xchg rcx, [rax]
xchg rcx, [rdx]
xchg [rax], rcx
{$endif}
end;
var
I1, I2: Integer;
begin
I1 := 19;
I2 := 564;
WriteLn('Swapping..');
WriteLn('I1: '+I1.ToString());
WriteLn('I2: '+I2.ToString());
Swap(I1, I2);
WriteLn('I1: '+I1.ToString());
WriteLn('I2: '+I2.ToString());
ReadLn;
end.
答案 0 :(得分:12)
我这样做:
type
TGeneric = class
public
class procedure Swap<T>(var Left, Right: T); static;
end;
class procedure TGeneric.Swap<T>(var Left, Right: T);
var
temp: T;
begin
temp := Left;
Left := Right;
Right := temp;
end;
这可用于交换任何类型的值。一种能让任何Java程序员哭泣的功能! ; - )
在我看来,编译器可以生成非常高效的代码。我认为您不必担心编译器能够生成有效的代码来执行分配。
对于T = Pointer
的32位,我们有:
push ebx mov ecx,[eax] mov ebx,[edx] mov [eax],ebx mov [edx],ecx pop ebx ret
对于T = Pointer
的64位,我们有:
mov rax,[rcx] mov r8,[rdx] mov [rcx],r8 mov [rdx],rax ret
FWIW,我并不热衷于使用const
参数的版本。问题中的代码应使用var
。但这种通用版本的类型安全性当然更可取。
答案 1 :(得分:5)
大卫的回答完全是解决问题的最明智的方法。
要探究为什么你的代码不起作用,请注意两件事
Integer
是x86和x64 RCX
,RDX
,R8
和R9
编译x86时,您的代码可以运行。在编译X64时,您假设参数传递给RAX
和RDX
,(如x86的EAX
,EDX
)这是错误的。所以你的代码看起来应该是
xchg rax, [rcx]
xchg rax, [rdx]
xchg [rcx], rax
您会注意到,如果没有更改,这也会失败 - 现在I1
和I2
都为零。这是因为您假设Integer
是64位类型,与指针不同,它不是(并且您没有进行任何类型检查 - 再次看到David的解决方案的好处)。如果你重新定义:
var
{$if defined(CPUX86)}
I1, I2: Integer;
{$else}
I1, I2: Int64;
{$ifend}
然后突然一切都按预期工作。到目前为止,还应该清楚为什么这不是最优雅的方法。