【问题标题】:How should I adapt my code for compatibility between TBytes and TIdBytes?我应该如何调整我的代码以实现 TBytes 和 TIdBytes 之间的兼容性?
【发布时间】:2013-09-21 20:16:18
【问题描述】:

我遇到了与“Delphi XE4 Indy compatibility issue between TBytes and TidBytes”中提到的相同的问题,即使用 Delphi XE4 编译时 TBytes(Delphi RTL) 和 TIdBytes(Indy) 数据类型之间的兼容性问题。我的问题的根源是代码不完全符合 Indy 的接口,并且某些函数在调用本机 Indy IO 过程时使用 TBytes 而不是 TIdBytes。

所以我想知道最好的解决方法是什么?

在我看来有两种方法:

  1. 重构项目中的所有函数以使用 TIdBytes 而不是 TBytes。

  2. 实现 TBytesToTidBytes 转换过程(将 TBytes 转换为 TIdBytes)并在进行上述原生 Indy 调用之前调用该过程。

哪种方法更好/最好?您对我如何做到这一点有任何其他想法吗?

仅供参考:我尝试使用 XE4 配置的项目可在 sourceforge 上在线获得:http://sourceforge.net/projects/indy10clieservr/?source=directory

建议的转换过程应该是这样的:

procedure TBytesToTIdBytes(const Input:TBytes, var Output: TIdBytes)
var 
    i,L : Integer;
    allocate : Boolean;
begin
    L := Length(Input);
    if(Length(Output) <> L) then 
    begin 
        SetLength(Output,L);
    end;
    if(L > 0) then 
        move(Pointer(Input)^,Pointer(Output)^,L);
end;

【问题讨论】:

  • 您的 allocate 变量没有任何作用,但您的长度检查很危险。如果数组具有相同的长度,那么您将不会重新分配数组,但如果目标数组的引用计数大于 1,您最终将覆盖您可能不打算这样做的数组。保存对数组的其他引用的代码可能会继续期待原始数据。无条件重新分配更安全。
  • 我明白你的意思。但是,为什么您认为 allocate 变量是无用的?它旨在指示目标数组之前是否已分配。
  • 它没用,因为它真正影响您是否调用SetLength 的唯一时间,对SetLength 的调用没有净效果。 allocate 的值唯一让你调用 SetLength 的时候是它为真。 allocate 为真的唯一方法是当Output 为空时,这意味着它是一个空数组。如果Input 是一个空数组,那么您不需要调用SetLength,因为它只会使Output 为空,我们知道它已经是空的。如果Input 不为空,那么即使不检查allocate 的值,长度比较也会评估为真无论如何
  • 注意到了!但是,由于我正在处理大量数据,我想更简单的类型转换解决方案更可取。谢谢。
  • 作为与不兼容类型作战的替代方法,您可以声明您的函数以接收开放数组中的数据。

标签: delphi indy10


【解决方案1】:

在较新的 Delphi 版本中,这两种类型在实现级别不同(TBytes 是最近 Delphi 版本中TArray&lt;Byte&gt; 的简单别名)。

所以我猜你可以使用这样的程序:

procedure TBytesToTIdBytes(const Input: TBytes; var Output: TIdBytes);
var L: integer;
begin
  L := Length(Input);
  SetLength(Output,L);
  move(Input[0],Output[0],L);
end;

这里move() 比循环快。

【讨论】:

  • 请务必在调用Move() 之前检查L &gt; 0,以避免出现越界错误。
  • 或使用move(Pointer(Intput)^,Pointer(Output)^,L)
  • @RemyLebeau OOB 错误只会在启用范围检查时发生。上面的代码在默认编译器设置下正常工作。
  • @ArnaudBouchez:现在比以后后悔更好。防御性编码是你的朋友。
【解决方案2】:

TBytesTIdBytes 都实现为动态数组,只是声明方式不同。 “政治正确”的解决方案是复制字节。但这会浪费大型数组的内存。一个更简单的解决方案是使用类型转换,这样您就可以利用数组的内部引用计数,例如:

type
  PIdBytes = ^TIdBytes;
var
  B1: TBytes;
  B2: TIdBytes;
begin
  B1 := ...;
  B2 := PIdBytes(@B1)^;
end;

或者简单地说:

var
  B1: TBytes;
  B2: TIdBytes;
begin
  B1 := ...;
  B2 := TIdBytes(B1);
end;

【讨论】:

  • 为什么不简单地B2 := TIdBytes(B1)
  • 那行得通。我有 C++ 背景,所以我更喜欢在类型转换中使用指针。
猜你喜欢
  • 2013-10-24
  • 2013-04-26
  • 2015-03-20
  • 2011-05-13
  • 2011-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多