使用 BytesToInt64() 将 TIdBytes 转换为 Integer 的意外结果

Unexpected results converting TIdBytes to Integer using BytesToInt64()

我正在使用 TIdUDPServer.OnUDPRead 事件读取 UDP 数据包。每个数据包中嵌入了一个 8 字节 QUint64,代表一个无线电频率。我正在尝试读取该频率。

所有使用 BytesToInt64() 的尝试都会导致错误的结果。我已通过使用 Wireshark 读取十六进制值并使用基于 Web 的十六进制到十进制转换器来验证数据是否正确。

我知道数据包中的频率从位置 23 开始,长度为 8 个字节。

procedure TWSJTxUDPClient.IdUDPServer1UDPRead(AThread:  TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
var
  FreqInt: Int64;

begin
  FreqInt := BytesToInt64(AData,23);
  LabelFreq.Caption := IntToStr(FreqInt);
end;

这是电线上的十六进制数据,从位置 23 开始:

00 00 00 00 00 6b f0 d0

表示频率为 7074000 赫兹。

我上面的代码生成的频率值为 58811137507983360。

我还通过在表示频率的字符串上使用 Ord() 函数读取每个字节来确认十六进制数据。

FreqStr := BytesToString(Adata,23,8);
Int8 := Ord(FreqStr[8]);

Int8 现在 = 208 - 0xd0 的正确值。对字节 5、6 和 7 执行相同操作。已确认。

所以我知道我缺少一些基本的东西。

您没有考虑字节序。

十进制 7074000 是十六进制 0x6BF0D0。十进制 58811137507983360 是十六进制 0xD0F06B00000000。看到相似之处了吗?它们的字节顺序相反。

您的数据包中的字节采用网络字节顺序(大端),但您的机器使用的是小端。您需要交换 Int64 的字节。您可以为此使用 Indy 的 GStack.NetworkToHost() 方法:

procedure TWSJTxUDPClient.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread; const AData: TIdBytes; ABinding: TIdSocketHandle);
var
  FreqInt: Int64;
begin
  FreqInt := BytesToInt64(AData, 23);
  FreqInt := Int64(GStack.NetworkToHost(UInt64(FreqInt)));
  LabelFreq.Caption := IntToStr(FreqInt);
end;