交换字变量的字节(低/高)的过程

发布于 2024-10-19 23:48:13 字数 244 浏览 1 评论 0原文

我有一个交换 Word 变量的字节(低/高)的过程(它与 System.Swap 函数执行相同的操作)。该过程在编译器优化关闭时有效,但在编译器优化打开时无效。 有人能帮我解决这个问题吗?

procedure SwapWord(VAR TwoBytes: word);   
asm
  Mov EBX, TwoBytes
  Mov AX, [EBX]
  XCHG AL,AH
  Mov [EBX], AX
end;

I have this procedure that swaps the bytes (low/high) of a Word variable (It does the same stuff as System.Swap function). The procedure works when the compiler optimization is OFF but not when it is ON.
Can anybody help me with this?

procedure SwapWord(VAR TwoBytes: word);   
asm
  Mov EBX, TwoBytes
  Mov AX, [EBX]
  XCHG AL,AH
  Mov [EBX], AX
end;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

阳光①夏 2024-10-26 23:48:13

最快:

function ReverseWord(w: word): word;
asm
   {$IFDEF CPUX64}
   mov rax, rcx
   {$ENDIF}
   xchg   al, ah
end;

如果您也想反转 DWORD:

function ReverseDWord(dw: cardinal): cardinal;
asm
  {$IFDEF CPUX64}
  mov rax, rcx
  {$ENDIF}
  bswap eax
end;

Fastest:

function ReverseWord(w: word): word;
asm
   {$IFDEF CPUX64}
   mov rax, rcx
   {$ENDIF}
   xchg   al, ah
end;

In case you want to reverse DWORD too:

function ReverseDWord(dw: cardinal): cardinal;
asm
  {$IFDEF CPUX64}
  mov rax, rcx
  {$ENDIF}
  bswap eax
end;
假情假意假温柔 2024-10-26 23:48:13

如果不保存/恢复,则无法在 ASM 代码中使用 EBX 寄存器。您的代码的更正版本是

procedure SwapWord_Working(VAR TwoBytes: word);   
asm
  PUSH EBX     // save EBX
  Mov EBX, TwoBytes
  Mov AX, [EBX]
  XCHG AL,AH
  Mov [EBX], AX
  POP EBX     // restore EBX
end;

You can't use EBX register in ASM code without saving/restoring it. The corrected version of your code is

procedure SwapWord_Working(VAR TwoBytes: word);   
asm
  PUSH EBX     // save EBX
  Mov EBX, TwoBytes
  Mov AX, [EBX]
  XCHG AL,AH
  Mov [EBX], AX
  POP EBX     // restore EBX
end;
我是男神闪亮亮 2024-10-26 23:48:13

让我有点惊讶的是,没有人提到“绝对”“黑客”,它已经存在了十多年,但没有引起太多关注……无论如何,这是我的两分钱

function SwapWordBytes(const Value: Word): Word;
var
  // shares memory with Value parameter
  LMemValue: array[0..1] of Byte absolute Value;
  // shares memory with Result
  LMemResult: array[0..1] of Byte absolute Result;
begin
  LMemResult[0] := LMemValue[1];
  LMemResult[1] := LMemValue[0];
end;

I'm a bit surprised that no one mentioned the absolute "hack" which is around for more than a decade but doesn't get too much spotlight... anyways here's my two cents

function SwapWordBytes(const Value: Word): Word;
var
  // shares memory with Value parameter
  LMemValue: array[0..1] of Byte absolute Value;
  // shares memory with Result
  LMemResult: array[0..1] of Byte absolute Result;
begin
  LMemResult[0] := LMemValue[1];
  LMemResult[1] := LMemValue[0];
end;
绝對不後悔。 2024-10-26 23:48:13

您是否考虑过使用编译器的 Swap 函数?

procedure TForm1.FormCreate(Sender: TObject);
var
  a: word;
begin
  a := $1234;
  a := Swap(a);
  Caption := IntToHex(a, 4)
end;

如果没有,则不需要 ASM(并且 ASM 可能在 64 位 Delphi 中不可用)。你可以这么做

procedure MySwap(var a: word);
var
  tmp: byte;
begin
  tmp := PByte(@a)^;
  PByte(@a)^ := PByte(NativeUInt(@a) + sizeof(byte))^;
  PByte(NativeUInt(@a) + sizeof(byte))^ := tmp;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  a: word;
begin
  a := $123456;
  MySwap(a);
  Caption := IntToHex(a, 4)
end;

,当然,这个主题有“一百万”个变体。

procedure MySwap(var a: word);
var
  tmp: byte;
type
  PWordRec = ^TWordRec;
  TWordRec = packed record
    byte1, byte2: byte;
  end;
begin
  with PWordRec(@a)^ do
  begin
    tmp := byte1;
    byte1 := byte2;
    byte2 := tmp;
  end;
end;

并且,非常简单地,

procedure MySwap(var a: word);
begin
  a := word(a shl 8) + byte(a shr 8);
end;

或者

procedure MySwap(var a: word);
begin
  a := lo(a) shl 8 + hi(a);
end;

Have you considered using the compiler's Swap function?

procedure TForm1.FormCreate(Sender: TObject);
var
  a: word;
begin
  a := $1234;
  a := Swap(a);
  Caption := IntToHex(a, 4)
end;

If not, you don't need ASM for this (and ASM will probably not be available in 64-bit Delphi). You can just do

procedure MySwap(var a: word);
var
  tmp: byte;
begin
  tmp := PByte(@a)^;
  PByte(@a)^ := PByte(NativeUInt(@a) + sizeof(byte))^;
  PByte(NativeUInt(@a) + sizeof(byte))^ := tmp;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  a: word;
begin
  a := $123456;
  MySwap(a);
  Caption := IntToHex(a, 4)
end;

and, of course, there are "a million" variations on this theme.

procedure MySwap(var a: word);
var
  tmp: byte;
type
  PWordRec = ^TWordRec;
  TWordRec = packed record
    byte1, byte2: byte;
  end;
begin
  with PWordRec(@a)^ do
  begin
    tmp := byte1;
    byte1 := byte2;
    byte2 := tmp;
  end;
end;

and, very briefly,

procedure MySwap(var a: word);
begin
  a := word(a shl 8) + byte(a shr 8);
end;

or

procedure MySwap(var a: word);
begin
  a := lo(a) shl 8 + hi(a);
end;
冰雪之触 2024-10-26 23:48:13

尽管 Serg 的答案肯定是正确的,正如对 Serg 答案的评论中指出的那样,但它效率不高。最快的显然是 Gabr 的答案中提供的代码,但由于您明确需要一个过程,而不是一个函数,因此以下将是 Serg 例程的首选版本:

procedure SwapWord_Working2 (VAR TwoBytes: word);
asm
  mov dx, [TwoBytes]  ;//[TwoBytes] = [eax] on x86 *[Note1]
  xchg dl, dh
  mov [TwoBytes], dx
end;

[注 1:] Serg 的函数版本很可能会,不适用于即将推出的 x64 Delphi 编译器。假设 Embarcadero 坚持使用 Win64 调用约定(其中 @TwoBytes 将通过 RCX 传递)的计划(Allen Bauer 在某处提到),此答案中提供的版本应该仍然可以在 x64 上运行。

Although Serg's answer is certainly correct, as pointed out in comments to Serg's answer, it's not efficient. The fastest would clearly be the code provided in Gabr's answer, but since you explicitly want a procedure, not a function, the following would be the preferred version of Serg's routine:

procedure SwapWord_Working2 (VAR TwoBytes: word);
asm
  mov dx, [TwoBytes]  ;//[TwoBytes] = [eax] on x86 *[Note1]
  xchg dl, dh
  mov [TwoBytes], dx
end;

[Note1:] Serg's version of the function will, in all likelihood, not work for the upcoming x64 Delphi compiler. Assuming Embarcadero stick to their plan (mentioned somewhere by Allen Bauer) of using the Win64 calling convention (where @TwoBytes would be passed via RCX) the version provided in this answer should still work on x64.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文