如何在Delphi中有效地交换指针?我试图交换整数类型的指针.以下示例I2在使用64位编译时工作为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.
Run Code Online (Sandbox Code Playgroud)
Dav*_*nan 11
我是这样做的:
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;
Run Code Online (Sandbox Code Playgroud)
这可用于交换任何类型的值.一种能让任何Java程序员哭泣的功能!;-)
在我看来,编译器生成非常高效的代码.我认为你不必担心编译器生成有效代码来执行赋值的能力.
对于32位T = Pointer我们有:
push ebx mov ecx,[eax] mov ebx,[edx] mov [eax],ebx mov [edx],ecx pop ebx ret
对于64位,T = Pointer我们有:
mov rax,[rcx] mov r8,[rdx] mov [rcx],r8 mov [rdx],rax ret
FWIW,我不热衷于您的版本使用const参数.问题中的代码应该使用var.但这种通用版本的类型安全性当然更可取.
大卫的答案完全是解决问题的最明智的方法.
要了解您的代码无法正常工作的原因,请注意两件事
Integer 是x86和x64的32位类型RCX,RDX,R8和R9编译x86时,您的代码可以正常工作.当编译为X64你假设参数被传递给RAX和RDX,(像86的EAX,EDX),这是错误的.所以你的代码应该是这样的
xchg rax, [rcx]
xchg rax, [rdx]
xchg [rcx], rax
Run Code Online (Sandbox Code Playgroud)
你会注意到,如果没有改变,这也失败-现在都I1和I2为零.这是因为你假设它Integer是64位类型,与指针不同,它不是(并且你没有进行任何类型的检查 - 再次看到David的解决方案的好处).如果您重新定义:
var
{$if defined(CPUX86)}
I1, I2: Integer;
{$else}
I1, I2: Int64;
{$ifend}
Run Code Online (Sandbox Code Playgroud)
然后突然一切都按预期工作.到目前为止,还应该清楚为什么这不是最优雅的方法.
| 归档时间: |
|
| 查看次数: |
859 次 |
| 最近记录: |