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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9732625/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 08:37:28  来源:igfitidea点击:

Can IntPtr be cast into a byte array without doing a Marshal.Copy?

c#.netintptr

提问by TTGroup

I want to get data from an IntPtr pointer into a byte array. I can use the following code to do it:

我想从 IntPtr 指针获取数据到字节数组中。我可以使用以下代码来做到这一点:

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

But the above code forces a copy operation from IntPtr into the byte array. It is not a good solution when the data in question is large.

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

Is there any way to cast an IntPtr to a byte array? For example, would the following work:

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

byte[] b = (byte[])intPtr

byte[] b = (byte[])intPtr

This would eliminate the need for the copy operation.

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

Also: how can we determine the length of data pointed to by IntPtr?

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

采纳答案by jeffora

As others have mentioned, there is no way you can store the data in a managedbyte[]without copying (with the current structure you've provided*). However, if you don't actually needit to be in a managed buffer, you can use unsafeoperations to work directly with the unmanaged memory. It really depends what you need to do with it.

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

All byte[]and other reference types are managed by the CLR Garbage Collector, and this is what is responsible for allocation of memory and deallocation when it is no longer used. The memory pointed to by the return of GetBufferis a block of unmanaged memory allocated by the C++ code and (memory layout / implementation details aside) is essentially completely separate to your GC managed memory. Therefore, if you want to use a GC managed CLR type (byte[]) to contain all the data currently held within your unmanaged memory pointed to by your IntPtr, it needs to be moved (copied) into memory that the GC knows about. This can be done by Marshal.Copyor by a custom method using unsafecode or pinvoke or what have you.

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

However, it depends what you want to do with it. You've mentioned it's video data. If you want to apply some transform or filter to the data, you can probably do it directly on the unmanaged buffer. If you want to save the buffer to disk, you can probably do it directly on the unmanaged buffer.

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

On the topic of length, there is no way to know the length of an unmanaged memory buffer unless the function that allocated the buffer also tells you what the length is. This can be done in lots of ways, as commenters have mentioned (first field of the structure, out paramtere on the method).

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

*Finally, if you have control of the C++ code it might be possible to modify it so that it is not responsible for allocating the buffer it writes the data to, and instead is provided with a pointer to a preallocated buffer. You could then create a managedbyte[]in C#, preallocated to the size required by your C++ code, and use the GCHandletype to pin it and provide the pointer to your C++ code.

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

回答by zmbq

You can't have a managed array occupy unmanaged memory. You can either copy the unmanaged data one chunk at a time, and process each chunk, or create an UnmanagedArrayclass that takes an IntPtrand provides an indexer which will still use Marshal.Copy for accessing the data.

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

As @Vinod has pointed out, you can do this with unsafecode. This will allow you to access the memory directly, using C-like pointers. However, you will need to marshal the data into managed memory before you call any unsafe .NET method, so you're pretty much limited to your own C-like code. I don't think you should bother with this at all, just write the code in C++.

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

回答by Vinod

Try this:

尝试这个:

byte* b = (byte*)intPtr;

Requires unsafe(in the function signature, block, or compiler flag /unsafe).

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

回答by Tsabo

Check out this Code Projectpage for a solution to working with unmanaged arrays.

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