代码之家  ›  专栏  ›  技术社区  ›  Danvil

如何在C中复制未管理的数据?它有多快?

c#
  •  15
  • Danvil  · 技术社区  · 14 年前

    我有两个非托管指针 IntPtr 希望在它们之间复制数据。我该怎么做?我知道方法 Marshal.Copy ,但它只能在非托管和托管之间复制。 第二部分:使用McCPy将非托管数据从非托管C/C++中复制慢吗?


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

    4 回复  |  直到 6 年前
        1
  •  16
  •   MusiGenesis    14 年前

    你可以使用 win32 memcpy 通过p-invoke函数。

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

    除了从托管代码调用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];
        }
    }
    

    这消除了平台依赖性,但是您需要非常小心边界检查和指针算法。

        2
  •  7
  •   Joe Amenta    6 年前

    如果您可以以.NET 4.6或更高版本为目标,请尝试 System.Buffer.MemoryCopy . 我相信这个方法和其他使用p/invoke的解决方案的主要区别在于,这个方法避免了较小规模的p/invoke,而只是直接进行复制。

    Here's .NET核心中的实施要点(最新版本为2018-06-19)。

        3
  •  5
  •   Mike C Chris Taylor    9 年前

    没有对性能发表评论,纯粹是因为我没有测试它。您可以通过interop从kernel32使用copymemory或movememory来实现与非托管拷贝相同的性能。

    这是copymemory的声明

    [DllImport("kernel32.dll")]
    static extern void CopyMemory(IntPtr destination, IntPtr source, uint length);
    
        4
  •  1
  •   MusiGenesis    14 年前

    CopyMemory 阿卡 RtlCopyMemory 阿卡 memcpy() 无论是从C还是C调用,速度都一样快(除了pinvoking方法本身的微小开销)。

    不过,要记住的是 复制存储器 仅当您确定源和目标范围不重叠时才应使用。如果它们确实重叠,则需要使用 MoveMemory 相反,速度会变慢。

    这是一份声明 CopyMeSomeMemory ,显示在.NET中可以执行相同操作的不同方法:

    [DllImport("kernel32.dll", EntryPoint = "RtlCopyMemory")]
    public static extern void CopyMeSomeMemory(IntPtr Destination, 
        IntPtr Source, uint Length);
    

    我想是为了记录 Buffer.BlockCopy 在.NET中,也只包装其中一个函数。