如何将大端序数字转换为Delphi本机数字

6

我想了解如何在Delphi中将大端序数转换为本机数。我正在移植一些C++代码,其中遇到了以下问题:

unsigned long blockLength  = *blockLengthPtr++ << 24;
blockLength |= *blockLengthPtr++ << 16;
blockLength |= *blockLengthPtr++ << 8;
blockLength |= *blockLengthPtr;

unsigned long dataLength  = *dataLengthPtr++ << 24;
dataLength |= *dataLengthPtr++ << 16;
dataLength |= *dataLengthPtr++ << 8;
dataLength |= *dataLengthPtr;

我对C++不熟悉,所以我不理解那些运算符的作用。


可能是如何转换大端和如何翻转最高位?的重复问题。 - Jeroen Wiert Pluimers
2个回答

22

Andreas的回答是一个很好的示例,展示了如何在纯Pascal中实现它,但它看起来仍然有点笨拙,就像C++代码一样。实际上,这可以通过一条单独的汇编指令来完成,但具体使用哪个取决于您是否使用32位或16位整数:

function SwapEndian32(Value: integer): integer; register;
asm
  bswap eax
end;

function SwapEndian16(Value: smallint): smallint; register;
asm
  rol   ax, 8
end;

2
这就是最佳解决方案! - Andreas Rejbrand
4
你不必在汇编函数中指定调用约定,@Michael,但是包含它是有用的,因为它们需要特定的调用约定才能正常工作。 - Rob Kennedy
1
是的,基本上就像Rob所说的那样。我知道这是默认的调用约定,而在那里放置'register;'是可选的,但明确说明它可以清楚地解释为什么要在(E)AX寄存器上操作。 - Mason Wheeler
6
这是一个不好的使用重载指令的例子,应该避免使用。整数和小整数类型非常接近,并且由编译器隐式转换。你可以将SmallInt值保留在Integer变量中(这是32位平台上的常见做法),但是如果使用重载的SwapEndian函数,则很可能会出现难以找到的错误。使用专门的名称(例如SwapEndian16和SwapEndian32)更安全、更好。 - kludg
1
在32位版本中,您应该使用Int32而不是integer,因为理论上integer类型可以是任何类型(在Delphi 1.0中它是16位的,在将来的版本中可能是64位),而Int32始终是32位的。同样,为了实现未来的兼容性,smallint应该改用Int16。 - HeartWare
显示剩余3条评论

4

将比特位的顺序反转:

procedure SwapEndiannessOfBits(var Value: cardinal);
var
  tmp: cardinal;
  i: Integer;
begin
  tmp := 0;
  for i := 0 to 8*sizeof(Value) - 1 do
    inc(tmp, ((Value shr i) and $1) shl (8*sizeof(Value) - i - 1));
  Value := tmp;
end;

要反转字节的顺序:

procedure SwapEndiannessOfBytes(var Value: cardinal);
var
  tmp: cardinal;
  i: Integer;
begin
  tmp := 0;
  for i := 0 to sizeof(Value) - 1 do
    inc(tmp, ((Value shr (8*i)) and $FF) shl (8*(sizeof(Value) - i - 1)));
  Value := tmp;
end;

我认为最后一个是您要寻找的。虽然可能有更快、更优美的解决方案。
免责声明:我的答案可能完全错误。我感到有点困惑。希望其他人能看到这个问题并提供更明确的答案!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接