7

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.

James Ko
  • 32,215
  • 30
  • 128
  • 239
  • Have you actually measured how much slower basic unsafe manual memory copy (similar to [Buffer.MemoryCopy](http://referencesource.microsoft.com/#mscorlib/system/buffer.cs,c2ca91c0d34a8f86) ) is? Since there are no runtime checks and resulting code is tiny there should be not much difference compared to block move operations (and really `memcpy` is frequently just manual loop too). – Alexei Levenkov Aug 11 '15 at 02:33
  • @AlexeiLevenkov No, but shouldn't a block-based one be faster? I'm not asking this because I'm dissatisfied with manual for-looping; I'm just curious to know if there's a better way. – James Ko Aug 11 '15 at 02:36
  • 1
    I have no idea, but since copying memory is limited by memory speed and CPU I'd not expect manual loop to be slower than CPU specific block copy. Note by the way that post is asking for equivalent of `memcpy` that does not necessary compile into block copy instructions... Consider to do your own benchmark . You can find more info about copying in similar questions like http://stackoverflow.com/questions/2658380/how-can-i-copy-unmanaged-data-in-c-sharp-and-how-fast-is-it and http://stackoverflow.com/questions/4707012/c-memcpy-vs-stdcopy). – Alexei Levenkov Aug 11 '15 at 02:47
  • 1
    The assertion that Marshal.Copy() "stopped being supported" is nonsense. It is alive and well in all .NET versions through 4.6, even available in PCL and WinRT apps. And the obvious solution to this non-existing problem. – Hans Passant Aug 12 '15 at 13:42

2 Answers2

4

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.

cel sharp
  • 149
  • 9
1

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.

usr
  • 168,620
  • 35
  • 240
  • 369