在Delphi XE4中使用类似于数组字节的AnsiString [英] Using AnsiString like byte of array in Delphi XE4

查看:318
本文介绍了在Delphi XE4中使用类似于数组字节的AnsiString的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

试图将 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆