Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a portable way to copy a block of memory in C#?

If you want to do a memory copy between two arrays, there's an Array.Copy function for that in .NET:

char[] GetCopy(char[] buf)
{
    char[] result = new char[buf.Length];
    Array.Copy(buf, result);
    return result;
}

This is usually faster than manually for-looping to copy all the characters in buf to result, because it's a block copy operation that simply takes a chunk of memory and writes it to the destination.

Similarly, if I was instead given a char* and an int specifying its size, what are my options? Here are the ones I've considered:

  • Buffer.BlockCopy: requires src and dst to be arrays
  • Buffer.MemoryCopy: exactly what I'm looking for, but only available on .NET Desktop
  • Marshal.Copy: stopped being supported in .NET 2.0

Or, if there's no alternative, is there some kind of way to construct an array from a pointer char* and a length int? If I could do that, I could just convert the pointers to arrays and pass them into Array.Copy.

I'm not looking for for-loops because as I said they're not very efficient compared to block copies, but if that's the only way I guess that would have to do.

TL;DR: I'm basically looking for memcpy(), but in C# and can be used in PCLs.

like image 753
James Ko Avatar asked Aug 11 '15 02:08

James Ko


2 Answers

You state that Marshal.Copy would not be supported any longer, however on the documentation of the Marshal class i can find no indication for that.

Quite the contrary, the class is available for the following framework versions: 4.6, 4.5, 4, 3.5, 3.0, 2.0, 1.1

One possible implementation of a utility function based on this method would be:

public static void CopyFromPtrToPtr(IntPtr src, uint srcLen,
                                    IntPtr dst, uint dstLen)
{
    var buffer = new byte[srcLen];
    Marshal.Copy(src, buffer, 0, buffer.Length);
    Marshal.Copy(buffer, 0, dst, (int)Math.Min(buffer.Length, dstLen));
}

However, it is quite possible, that copying the bytes from IntPtr to byte[] and back again negates any possible performance gain over pinning the unsafe memory and copying it in a loop.

Depending on how portable the code needs to be, you could also consider using P/Invoke to actually use the memcpy method. This should work well on Windows 2000 and onwards (all systems that have the Microsoft Visual C Run-Time Library installed).

[DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
static extern IntPtr memcpy(IntPtr dst, IntPtr src, UIntPtr count);

Edit: The second approach would not be suited for portable class libraries, the first however would be.

like image 78
cel sharp Avatar answered Nov 10 '22 23:11

cel sharp


I don't recall what built-in APIs the BCL has but you can copy the BCL memcpy code and use it. Use Reflector and search for "memcpy" to find it. Unsafe code is perfectly defined and portable.

like image 1
usr Avatar answered Nov 10 '22 21:11

usr