5

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.
4

2 に答える 2

5

デビッドの答えは、問題を解決するための最も賢明なアプローチです。

ただし、コードが機能しない理由を調べるには、2 つの点に注意してください。

  • Integerx86 と x64 の両方の 32 ビット型です。
  • x64 では、引数は (順番に) RCXRDXR8およびに渡されます。R9

x86 用にコンパイルすると、コードが機能します。X64 用にコンパイルする場合、(x86 の のように)RAXとに引数が渡されていると想定していますが、これは間違っています。したがって、コードは次のようになりますRDXEAXEDX

  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}

その後、突然、すべてが期待どおりに機能します。ここまでで、これが最もエレガントなアプローチではない理由も明らかになっているはずです。

于 2014-06-25T19:16:47.930 に答える