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

时间:2012-03-16 05:57:46

标签: c# .net intptr

我想将IntPtr指针中的数据转换为字节数组。我可以使用以下代码来执行此操作:

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

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

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

byte[] b = (byte[])intPtr

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

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

4 个答案:

答案 0 :(得分:22)

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

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

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

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

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

答案 1 :(得分:8)

试试这个:

byte* b = (byte*)intPtr;

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

答案 2 :(得分:2)

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

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

答案 3 :(得分:1)

查看此Code Project页面,了解使用非托管阵列的解决方案。