vic*_*ico 1 delphi string indy10 delphi-xe
试图将Delphi 2007项目移动到XE4.在Delphi 2007我用函数读取使用从插座字节数组Indy直接.我传递AnsiString给这个函数的字节数组的var参数:
var data:AnsiString;
AContext.Connection.IOHandler.ReadBytes(TIDBytes(Data), PacketLength-PacketLengthDelta-1, False);
Run Code Online (Sandbox Code Playgroud)
在Dlphi XE当我尝试concatinate Data到另一个字符串我有access violation错误.
现在我试图用更简单的代码模拟这个问题:
TIdBytes = array of Byte;
procedure fill(var b: TIDBytes);
begin
setlength(b,5);
b[0]:=61;
b[1]:=61;
b[2]:=61;
b[3]:=61;
b[4]:=61;
//original function used move function
end;
procedure TMainForm.FormCreate(Sender: TObject);
var s: ansistring ;
begin
fill( TIDBytes(s) );
Showmessage(s);
end;
Run Code Online (Sandbox Code Playgroud)
现在我期待====在消息框中看到类似的东西,但我得到了空的.我认为XE AnsiString的行为与Delphi 2007 Ansistring相同,你可以在两种情况下都像字节数组一样使用它们.
解决填充带有字节问题的AnsiString的最佳方法是什么?
将强制AnsiString转换为字节数组永远无效.那段代码总是坏了,你很幸运(或者根据你的观点不幸).
托管字符串类型,就像动态数组一样,具有额外的信息有效负载,元数据存储在数据有效负载之前.此元数据包括引用计数,长度等.但字符串的元数据与动态数组的元数据不同.简单地说,字符串不是动态数组.您的重新解释演员表完全无效.它在旧版本的Delphi中无效,在现代版本中它也同样无效.
真正发生的事情是,随着Unicode支持的引入,元数据的大小发生了变化.AnsiString已扩展元数据.它现在包含,例如,字符串的代码页.
现在,当您调用时SetLength,将分配足够大的元数据和有效负载的内存块.假设在地址P处分配了内存.您的变量(字符串或动态数组)保存的地址设置为P +元数据大小.当您解除分配对象时,系统将移至P - 元数据大小并FreeMem使用该地址进行调用.这是踢球者.分配时使用动态数组元数据的大小,但是在解除分配时使用字符串元数据的大小.结果?繁荣!您刚刚调用FreeMem了一个无效的地址,一个尚未分配给您的地址.
处理这个问题的正确方法是给Indy函数提供它想要的东西.即一个字节数组.如果需要传输到字符串变量,请将字节数组的内容复制到新字符串中.例如使用TEncoding.Default.GetString().
| 归档时间: |
|
| 查看次数: |
4589 次 |
| 最近记录: |