如何将指针转换回字节数组(或流)?

use*_*144 2 delphi delphi-7

我有一个函数,它创建指向Stream数据的指针.

function StreamToByteArray(Stream: TStream): Pointer;
var
  ByteArr: array of Byte;
begin
  if Assigned(Stream) then
  begin
    Stream.Position := 0;
    SetLength(ByteArr, Stream.Size);
    Stream.Read(ByteArr[0], Stream.Size);
  end
  else
    SetLength(ByteArr, 0);
  result := @ByteArr[0];
end;
Run Code Online (Sandbox Code Playgroud)

如何将其转换回来,从指针转换为动态字节数组,然后将内容保存到流中.或者也许可以直接从指针加载流?

感谢帮助.

Cos*_*und 12

哎呀,这个代码(不幸的是)非常糟糕.你的函数返回一个指向ByteArr数组的指针,但遗憾的是当函数存在时,该数组的范围超出了范围:你实际上是在返回一个无效的指针!即使错误没有立即弹出,你也有潜在的访问冲突.

更长的解释

A Pointer是一种危险的结构:它不包含数据,它只是说数据存在的位置.您的无类型示例Pointer是最困难的指针类型,它没有说明给定地址中存在的数据.它可能指向您从流中读取的某些字节,可能指向字符串甚至某些类型的图片.您甚至无法知道给定地址的数据量.

指针概念与分配内存的概念密切相关.我们使用许多不同的技术来分配内存,使用局部变量,全局变量,对象,动态数组等.在您的示例函数中,您使用的是动态数组,即array of Byte.编译器可以很好地屏蔽你从分配和重新分配内存的内部,你可以简单地SetLength()用来说明数组应该有多大.事情很好,因为动态数组是Delphi中的托管数据结构:编译器会跟踪您如何使用动态数组,并在不再需要动态数组时立即释放相关内存.就编译器而言,当函数存在时,不再需要相关的内存.

当你做的时候:

Result := @ByteArr[0];
Run Code Online (Sandbox Code Playgroud)

您实际上是为编译器分配的内存块获取地址.由于您使用的是非常低级别的结构(Pointer),编译器无法跟踪您对内存的使用情况,因此当函数存在时它将释放内存.这将留下指向未分配内存的指针.

如何Pointer从函数中正确返回a

首先,如果可能的话,你应该避免指针:它们是低级的,编译器无法帮助进行类型安全或解除分配,它们很容易出错.当你确实指出错误时,错误通常是访问冲突,并且它们很难跟踪.

也就是说,如果你真的想要返回一个指针,你应该返回一个显式分配内存的指针,所以你知道编译器不会为你释放它.当你这样做时,确保接收代码知道它负责内存(应该在不再需要内存时释放内存).例如,您的函数可以像这样重写:

function StreamToByteArray(Stream: TStream): Pointer;
begin
  if Assigned(Stream) then
    begin
      Result := AllocMem(Stream.Size);
      Stream.Position := 0;
      Stream.Read(Result^, Stream.Size);
    end
  else
    Result := nil;
end;
Run Code Online (Sandbox Code Playgroud)

如何将指针更改回array of byteTStream

答案是,没有办法改变它.指针就是指向某些随机数据的指针.字节数组比它包含的数据多.A TStream更加抽象:它是一个告诉您如何检索数据的界面,它不一定包含任何数据.例如,TFileStream(这TStream)未持有任何数据的字节:所有的数据在磁盘上的文件中.

  • 你不应该将它转换回来,即使你知道它是`byte of array'的第一个字节:记住动态数组是一个托管结构,当你直接使用内存结构时,你基本上是弄乱它的用户计数器(编译器不知道你在做什么).即使你今天*和*你的*版本的Delphi可以做到这一点,这将依赖于未来版本的Delphi中可能会改变的实现细节.更不用说这样做时没有类型安全.如果你需要的话,返回一个`byte of array`有什么问题? (4认同)