如何在C#中复制非托管数据以及速度有多快?

Dan*_*vil 14 c#

我有两个非托管指针,IntPtr并希望在它们之间复制数据.我怎样才能做到这一点?我知道这个方法Marshal.Copy,但它只能在非托管和托管之间进行复制.第二部分:使用memcpy从C#中复制非托管数据比在非托管C/C++中复制更慢吗?


编辑:我会对平台独立实现特别感兴趣.

Ash*_*Ash 16

您可以通过P-Invoke 使用win32 memcpy函数.

[DllImport("msvcrt.dll",  SetLastError = false)]
static extern IntPtr memcpy(IntPtr dest, IntPtr src, int count);
Run Code Online (Sandbox Code Playgroud)

除了从托管代码调用win32函数的(轻微)开销之外,实际的复制性能应该与使用相同函数的C/C++代码相同.

不要忘记您也可以使用不安全的块(和编译器选项),并且一次只能复制一个字节/ int/long的数据:

unsafe
{
    // srcPtr and destPtr are IntPtr's pointing to valid memory locations
    // size is the number of long (normally 4 bytes) to copy
    long* src = (long*)srcPtr;
    long* dest = (long*)destPtr;
    for (int i = 0; i < size / sizeof(long); i++)
    {
        dest[i] = src[i];
    }
}
Run Code Online (Sandbox Code Playgroud)

这将删除平台依赖关系,但您需要非常小心边界检查和指针算法.

  • 使用此签名调用它会为我生成[pInvokeStackImbalance](http://msdn.microsoft.com/en-us/library/0htdy0k3.aspx).但是通过使用[pinvoke.net]上的签名解决了这个问题(http://www.pinvoke.net/default.aspx/msvcrt/memcpy.html). (6认同)
  • 感谢您提供不安全的代码,但我的 C/C++ 经验警告我,尝试重新实现 memcpy 时会遇到一堆问题...... (2认同)

Joe*_*nta 9

如果可以使用.NET 4.6或更高版本,请尝试使用System.Buffer.MemoryCopy.我相信这个和使用P/Invoke的其他解决方案之间的主要区别在于,这种方法避免了较小尺寸的P/Invoke,只是直接进行复制.

以下是 .NET Core中实现的内容(最新版本为2018-06-19).


Chr*_*lor 5

没有对性能发表评论,纯粹是因为我没有测试过它.通过使用来自Kernel32的CopyMemory或MoveMemory,可以通过interop实现与非托管副本相同的性能.

这是CopyMemory的声明

[DllImport("kernel32.dll")]
static extern void CopyMemory(IntPtr destination, IntPtr source, uint length);
Run Code Online (Sandbox Code Playgroud)