将 C# 函数移动到 Delphi

Moving C# function to Delphi

我在 C# 中有下一个函数,我需要转换为 Delphi。 C# 有 BitConverter 可以轻松完成,但我不知道如何在 Delphi.

/// Reads a 4-byte floating point value from the current stream 
public override float ReadSingle(float sg)
{
    byte[] temp = BitConverter.GetBytes( sg );
    Array.Reverse(temp);
    float returnVal = BitConverter.ToSingle(temp, 0);
    return returnVal;
}

我完成了:

procedure ReverseBytes(Source, Dest: Pointer; Size: Integer);
var
  Index: Integer;
begin
  for Index := 0 to Size - 1 do
    Move(Pointer(LongInt(Source) + Index)^,
        Pointer(LongInt(Dest) + (Size - Index - 1))^ , 1);
end;
function GetBytes(sg:single):Tbytes;
begin
   result:=??????
end;

function ReadSingle(sg:single):single;
var dest,temp:Tbytes;
begin
 temp := GetBytes(sg); //How todo ???
 ReverseBytes(temp,dest,length(temp));
 result:=dest;
end;

您正在尝试将大端表示形式的单个浮点数转换为小端表示形式。

此功能将为您完成:

function ReadSingle(sg:single):single;
begin
  ReverseBytes(@sg,@Result,SizeOf(Single));
end;

具有 TSingleHelper 的现代 Delphi 版本可以像这样反转字节:

function ReadSingle(sg:Single):single;
begin
  Result.Bytes[0] := sg.Bytes[3];
  Result.Bytes[1] := sg.Bytes[2];
  Result.Bytes[2] := sg.Bytes[1];
  Result.Bytes[3] := sg.Bytes[0];
end;

注:浮点参数在fpu寄存器中传递。将缺陷浮点数加载到 fpu 寄存器会触发异常。在更正字节顺序之前,我宁愿避免将传入数据视为浮点数。

一个例子:

function ReadSingle(sg:PSingle): Single;
begin
  ReverseBytes(sg,@Result,SizeOf(Single));
end;

正如@Rudy 所指出的,ReverseBytes 函数对于 64 位编译器是不正确的。 LongInt() 转换必须在两个地方替换为 NativeUInt()。然后它适用于 32 位编译器和 64 位编译器。 winsock 库中还有一些系统函数可供使用,ntohl()


这是 here 的另一个 ReverseBytes 替代方案:

procedure ReverseBytes(Source, Dest: Pointer; Size: Integer);
begin
  Dest := PByte( NativeUInt(Dest) + Size - 1);
  while (Size > 0) do 
  begin
    PByte(Dest)^ := PByte(Source)^;
    Inc(PByte(Source));
    Dec(PByte(Dest));
    Dec(Size);
  end;
end;

对于网络字节序到主机字节序的转换(在Delphi的情况下,从大端到小端),可以使用函数ntohlntohs 来自 WinSockWinSock2:

uses
  WinSock2;

type
  PUInt32 = ^UInt32;
  PUInt64 = ^UInt64; 

function ReadSingle(sg: Single): Single;
begin
  Result := ntohl(PUInt32(@sg));
end;

function ReadDouble(db: Double): Double;
begin
  Result := UInt64(ntohl(PUInt64(@db) shr 32)) or
            UInt64(ntohl(PUInt32(@db))) shl 32;
end;

或者,如果您想使用 ReverseBytes,则将其更新为现代:

function ReverseBytes(Source, Dest: Pointer; Size: Integer);
var
  I: Integer;
begin
  for I := 0 to Size - 1 do
    PByte(Dest)[I] := PByte(Source)[Size - I - 1];
end;

function ReadSingle(sg: Single): Single;
begin
  ReverseBytes(@sg, @Result, SizeOf(Single));
end;

function ReadDouble(db: Double): Double;
begin
  ReverseBytes(@db, @Result, Sizeof(Double));
end;

如果您的 Delphi 旧版本不允许 PByte-as-array 语法,您可以使用 PAnsiChar 而不是 PByte,但是shshshsh!,那是黑客,所以不要告诉别人我说过。