【问题标题】:Why use string[1] rather than string while using readbuffer为什么在使用 readbuffer 时使用 string[1] 而不是 string
【发布时间】:2010-07-07 07:37:48
【问题描述】:

我有这样的记录

  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]有什么区别

【问题讨论】:

  • 你的那条记录真的是一个奇怪的野兽,它被标记为打包记录(拒绝编译器优化)但它包含一个“字符串”,它不应该直接流式传输,也不应该是与 Delphi 之外的任何东西接口。我很确定您想删除 `packed` 或将 ImageSource 更改为如下内容:` ImageSource: string[128] ` - 即,使用旧的帕斯卡风格,固定长度的字符串。

标签: delphi delphi-2007 delphi-2006


【解决方案1】:

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

签名是:

procedure ReadBuffer(var Buffer; Count: Longint);

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

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

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

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

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-22
      • 2018-10-31
      • 2010-12-31
      • 1970-01-01
      • 1970-01-01
      • 2015-02-12
      • 1970-01-01
      相关资源
      最近更新 更多