可以在不执行Marshal.Copy的情况下将IntPtr转换为字节数组吗?

TTG*_*oup 23 .net c# intptr

我想从IntPtr指针获取数据到字节数组.我可以使用以下代码来执行此操作:

IntPtr intPtr = GetBuff();
byte[] b = new byte[length];
Marshal.Copy(intPtr, b, 0, length);
Run Code Online (Sandbox Code Playgroud)

但是上面的代码强制从IntPtr到字节数组的复制操作.当有问题的数据很大时,这不是一个好的解决方案.

有没有办法将IntPtr转换为字节数组?例如,以下工作:

byte[] b = (byte[])intPtr

这将消除复制操作的需要.

另外:我们如何确定IntPtr指向的数据长度?

jef*_*ora 23

正如其他人所提到的,没有办法可以在没有复制的情况下将数据存储在托管中 byte[](使用您提供的当前结构*).但是,如果您实际上不需要它在托管缓冲区中,则可以使用unsafe操作直接使用非托管内存.这真的取决于你需要做什么.

所有byte[]和其他引用类型都由CLR垃圾收集器管理,这是在不再使用时负责内存分配和释放的原因.返回指向的内存GetBuffer是由C++代码分配的非托管内存块,(除了内存布局/实现细节)基本上与GC托管内存完全分开.因此,如果要使用GC托管CLR类型(byte[])来包含当前保存在您指向的非托管内存中的所有数据IntPtr,则需要将其移动(复制)到GC知道的内存中.这可以Marshal.Copy通过自定义方法unsafe或使用代码或pinvoke或您拥有的内容来完成.

但是,这取决于你想用它做什么.你已经提到了它的视频数据.如果要对数据应用某些转换或过滤器,则可以直接在非托管缓冲区上执行此操作.如果要将缓冲区保存到磁盘,则可以直接在非托管缓冲区上执行此操作.

关于长度的主题,除非分配缓冲区的函数也告诉您长度是多少,否则无法知道非托管内存缓冲区的长度.这可以通过许多方式完成,正如评论者所提到的(结构的第一个领域,方法的参数).

*最后,如果您可以控制C++代码,则可以对其进行修改,以便它不负责分配将数据写入的缓冲区,而是提供指向预分配缓冲区的指针.然后,您可以在C#中创建托管 byte[],预分配到C++代码所需的大小,并使用该GCHandle类型来固定它并提供指向C++代码的指针.


Vin*_*nod 8

试试这个:

byte* b = (byte*)intPtr;
Run Code Online (Sandbox Code Playgroud)

需要不安全(在函数签名,块或编译器标志中/unsafe).

  • 你应该提到这需要函数签名中的`unsafe`关键字或一对花括号:`usafe {...}` (5认同)
  • 您的项目需要配置为允许不安全的代码,答案中陈述的代码需要包装在不安全的地方(如@MikeBantegui所说),最重要的是,这为您提供了一个非托管内存的非托管指针,而不是CLR字节[]参考 (2认同)