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

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

IntPtr intPtr = GetBuff(); byte[] b = new byte[length]; Marshal.Copy(intPtr, b, 0, length); 

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

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

byte[] b = (byte[])intPtr

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

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

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

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

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

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

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

试试这个:

 byte* b = (byte*)intPtr; 

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

您不能让托管arrays占用非托管内存。 您可以一次复制一个块的非托管数据,并处理每个块,或者创建一个UnmanagedArray类,它接受一个IntPtr并提供一个仍然使用Marshal.Copy访问数据的索引器。

正如@Vinod指出的那样,你可以用unsafe代码来做到这一点。 这将允许您使用类似C的指针直接访问内存。 但是,在调用任何不安全的.NET方法之前,您需要将数据封送到托管内存中,因此您几乎只限于自己的类C代码。 我认为你根本不应该为此烦恼,只需用C ++编写代码即可。

查看此“代码项目”页面,了解使用非托管arrays的解决方案。