How can I copy unmanaged data in C# and how fast is it?
I have two unmanaged pointers in the form开发者_如何学JAVA of IntPtr
and want to copy data between them. How can I do this? I know the method Marshal.Copy
, but it can only copy between unmanaged and managed.
And the second part: Is copying unmanaged data from C# slower than doing it in unmanaged C/C++ using memcpy?
Edit: I would be especially interested in a platform independet implementation.
You can use the win32 memcpy function via P-Invoke.
[DllImport("msvcrt.dll", SetLastError = false)]
static extern IntPtr memcpy(IntPtr dest, IntPtr src, int count);
Apart from the (slight) overhead calling a win32 function from managed code, the actual copy performance should be the same as C/C++ code that uses the same function.
Don't forget that you can also use an unsafe block (and compiler option) and simply copy the data one byte/int/long at a time:
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];
}
}
This removes the platform dependency, but you need to be very careful with the bounds checking and pointer arithmetic.
Try System.Buffer.MemoryCopy
, see the bottom of the page for supported target frameworks.
I believe that the main difference between this and the other solutions that use P/Invoke is that this method avoids the P/Invoke for smaller sizes and just does the copying directly.
Here's the guts of the implementation in .NET Core (latest as of 2020-09-04).
Without making comments on performance, purely because I have not tested it. You can achieve the same performance as unmanaged copy by using either CopyMemory or MoveMemory from Kernel32 via interop.
Here is the declaration for CopyMemory
[DllImport("kernel32.dll")]
static extern void CopyMemory(IntPtr destination, IntPtr source, uint length);
You could look at System.Runtime.CompilerServices.Unsafe.CopyBlock
It seems to allow you to copy bytes from the source address (designated by a void*) to the destination address (designated by a void*).
It also overriden to support ref byte
as the source and destination.
[edit] Disappointingly it appears not to be implemented in Mono
[edit] For those who are interested in this and using Unity, you should instead look to Unity's UnsafeUtility.MemCpy
CopyMemory
aka RtlCopyMemory
aka memcpy()
will be just as fast whether called from C# or C (other than the tiny overhead of PInvoking the method itself).
Something to keep in mind, though, is that CopyMemory
should only be used when you're sure that the source and destination ranges do not overlap. If they do overlap, you need to use MoveMemory
instead, which will be slower.
Here is a declaration for CopyMeSomeMemory
, showing how many different ways you can do the same thing in .Net:
[DllImport("kernel32.dll", EntryPoint = "RtlCopyMemory")]
public static extern void CopyMeSomeMemory(IntPtr Destination,
IntPtr Source, uint Length);
For the record, I think Buffer.BlockCopy
in .Net just wraps one of these functions, too.
精彩评论