4

我有这样的记录

  TEmf_SrectchDIBits = packed record
    rEMF_STRETCHDI_BITS: TEMRStretchDIBits;
    rBitmapInfo: TBitmapInfo;
    ImageSource: string;
  end;
  ---
  ---
  RecordData: TEmf_SrectchDIBits;

如果我像这样使用 TStream 将数据读入其中,则会发生异常

SetLength(RecordData.ImageSource, pRecordSize);

EMFStream.ReadBuffer(RecordData.ImageSource,pRecordSize) 

但如果我使用下面的代码,它工作正常

SetLength(RecordData.ImageSource, pRecordSize);

EMFStream.ReadBuffer(RecordData.ImageSource[1], pRecordSize);

那么使用 String 和 String[1] 有什么区别

4

2 回答 2

12

不同之处在于与 .ReadBuffer 方法的签名有关的细节。

签名是:

procedure ReadBuffer(var Buffer; Count: Longint);

如您所见,Buffer 参数没有类型。在这种情况下,您是说要访问基础变量。

然而,一个字符串由两部分组成,一个指针(变量的内容)和字符串(变量指向 this)。

因此,如果只给 ReadBuffer 一个字符串变量,它将有 4 个字节来存储数据到字符串变量中,这不会很好,因为字符串变量应该保存一个指针,而不仅仅是任何随机二进制数据. 如果 ReadBuffer 写入超过 4 个字节,它将用新数据覆盖内存中的其他内容,这是一个潜在的灾难性行为。

通过将 [1] 字符传递给var参数,您可以让 ReadBuffer 访问字符串变量指向的数据,这正是您想要的。毕竟,您想更改字符串内容。

此外,请确保您已将字符串变量的长度设置为足够大,以容纳您正在读入的任何内容。

另外,最后一点,我无法验证。在较旧的 Delphi 版本中,字符串变量包含 1 字节字符。在较新的版本中,我认为它们是两个,由于 unicode,因此该代码在较新版本的 Delphi 中可能无法按预期工作。您可能想改用字节数组或堆内存。

于 2010-07-07T07:49:48.173 回答
5

字符串类型实际上是作为指向我们可以称为“字符串描述符块”的指针来实现的。基本上,您有一定程度的间接性。该块在负偏移处包含一些字符串控制数据(引用计数、长度以及在更高版本中的字符集信息),在正偏移处包含字符串字符。字符串变量是指向解密块的指针(如果打印 SizeOf(stringvar) 会得到 4),当您处理字符串时,编译器知道在哪里可以找到字符串数据并处理它们。但是当使用无类型参数(var Buffer;)时,编译器并不知道,它只会访问“Buffer”处的内存,但使用一个作为指针的字符串变量到字符串块,而不是实际的字符串字符。使用 string[1] 传递第一个字符数据的位置。

于 2010-07-07T08:48:19.343 回答