James Ko
James Ko

Reputation: 34609

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:

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.

Upvotes: 7

Views: 2621

Answers (2)

usr
usr

Reputation: 171226

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.

Upvotes: 1

cel sharp
cel sharp

Reputation: 149

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.

Upvotes: 4

Related Questions