将 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的情况下,从大端到小端),可以使用函数ntohl
和ntohs
来自 WinSock
或 WinSock2
:
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!,那是黑客,所以不要告诉别人我说过。
我在 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的情况下,从大端到小端),可以使用函数ntohl
和ntohs
来自 WinSock
或 WinSock2
:
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!,那是黑客,所以不要告诉别人我说过。