在Delphi XE4中使用类似于数组字节的AnsiString [英] Using AnsiString like byte of array in Delphi XE4
问题描述
试图将 Delphi 2007
项目移至 XE4
。在 Delphi 2007
中,我使用的函数直接使用 Indy
从套接字读取字节数组。我将 AnsiString
传递给此函数的var参数转换为字节数组:
Trying to move Delphi 2007
project to XE4
. In Delphi 2007
I was using function that reads byte array from socket using Indy
directly. I passed AnsiString
casted to array of byte to var parameter of this function:
var data:AnsiString;
AContext.Connection.IOHandler.ReadBytes(TIDBytes(Data), PacketLength-PacketLengthDelta-1, False);
在 Dlphi XE
中数据
到另一个字符串,我遇到了访问冲突
错误。
In Dlphi XE
when I try to concatinate Data
to another string I got access violation
error.
现在,我正在尝试用更简单的代码模拟此问题:
Now I'm trying to simulate this problem in more simple code:
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;
现在我希望看到类似 ====
在消息框中,但是我得到了一个空的。我认为XE AnsiString的行为类似于Delphi 2007 Ansistring,在两种情况下都可以像字节数组一样使用它们。
Now I expect to see something like ====
in message box, but I got empty one. I supposed that XE AnsiString acts the same like Delphi 2007 Ansistring and you can use them like byte array in both cases.
解决用字节填充AnsiString的最佳方法是什么?
What is the best way to solve filling AnsiString with bytes problem?
推荐答案
将 AnsiString
强制转换为字节数组永远无效。该代码始终被破坏,您很幸运(或不幸的话,具体取决于您的观点)。
It was never valid to cast an AnsiString
to a byte array. That code was always broken and you got lucky (or unlucky depending on your point of view).
托管字符串类型,就像动态数组一样,具有额外的信息有效负载,即元数据,该有效负载存储在数据有效负载之前。该元数据包括引用计数,长度等。但是字符串的元数据与动态数组的元数据不同。简而言之,字符串不是动态数组。您的重新解释演员表完全无效。在旧版本的Delphi中无效,而在现代版本中无效。
Managed string types, just like dynamic arrays, have an extra payload of information, metadata, that is stored just before the data payload. This metadata includes reference count, length etc. But the metadata for strings is not the same as for dynamic arrays. Simply put, a string is not a dynamic arrays. Your reinterpret cast is completely invalid. It was invalid in the old versions of Delp and it's just as invalid in the modern versions.
真正的含义是元数据的大小随着Unicode支持的引入而改变。 AnsiString
的元数据已扩展。现在,它包含例如字符串的代码页。
What's really going on under the hood is that the size of the metadata has changed with the introduction of Unicode support. The metadata for AnsiString
has been expanded. It now contains, for instance, the code page of the string.
现在,当您调用 SetLength
时,分配足以容纳元数据和有效负载的内存块。假设内存分配在地址P处。变量(字符串或动态数组)保存的地址设置为P +元数据大小。当您要取消分配对象时,系统将移至P-元数据大小,并使用该地址调用 FreeMem
。这是踢脚线。分配时使用动态数组元数据的大小,而取消分配时使用字符串元数据的大小。结果?繁荣!您只是在无效的地址(尚未分配给您的地址)上调用 FreeMem
。
Now, when you call SetLength
, a block of memory large enough for both metadata and payload is allocated. Suppose that memory is allocated at address P. The address that your variable (string or dynamic array) holds is set to P + metadata size. When you come to deallocate the object, the system moves to P - metadata size and calls FreeMem
with that address. And here's the kicker. You use the size of a dynamic array metadata when you allocate, but the size of a string meta data when you deallocate. The result? BOOM! You just called FreeMem
on an invalid address, one that has not been allocated to you.
正确的地址处理这是为了给Indy函数提供所需的功能。即字节数组。如果您需要传输到字符串变量,请将字节数组的内容复制到新字符串中。例如使用 TEncoding.Default.GetString()
。
The correct way to handle this is to give the Indy function what it wants. Namely a byte array. If you need to transfer to a string variable, copy the byte array's content into a new string. For instance using TEncoding.Default.GetString()
.
这篇关于在Delphi XE4中使用类似于数组字节的AnsiString的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!