Memcpy Function in C#

memcpy function in c#

As already said it depends what you are trying to do...
So you can consider one of these... check the links:

  • Array.Copy
  • Object.MemberwiseClone
  • ICloneable Interface

There may be other possible options based on your needs...

What is the C# equivalent of memcpy array to int?

It really seems you just want to use

  • BitConverter.ToInt32 Method

Returns a 32-bit signed integer converted from four bytes at a
specified position in a byte array

int offset =  BitConverter.ToInt32(somebyteData,0);

Note : Beware of the endianness

Or you could just use the the shift operators

  • << operator (C# Reference)

  • <<= operator (C# Reference)

  • >> operator (C# Reference)

  • >>= operator (C# Reference)

Though if you want to use memcpy, It depends what overloads you need, you can just P/invoke it if you want

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

However, for pointers the last 2 are probably good equivalents, with Marshal.Copy having by far the most versatility

  • Buffer.BlockCopy

Copies a specified number of bytes from a source array starting at a
particular offset to a destination array starting at a particular
offset.

  • Array.Copy

Copies a range of elements in one Array to another Array and performs
type casting and boxing as required.

  • Unsafe.CopyBlock Method

Copies a number of bytes specified as a long integer value from one
address in memory to another.

  • Marshal.Copy

Copies data from a managed array to an unmanaged memory pointer, or
from an unmanaged memory pointer to a managed array.

C++ memcpy to c# equivalent

This is performing a kind of binary serialization for structured data. Check out BinaryWriter for similar functionality in .NET. This can be attached to any stream, but you can use MemoryStream if you want to use a byte array as the backing store (like in the C code.)

Note also (as another poster mentioned), you may have to watch for Endian-ness and other platform-specific issues, at least assuming you want to be binary-compatible with the C program. It's hard to say more without knowing the platform used for the original program and how you're inter-operating with it, if at all. For instance, is that data saved to a file that you want to be able to load?


UPDATE:

Based on your edit, it looks like the original code is Endian-aware. You can use BitConverter.IsLittleEndian to check the Endian-ness of your platform and make equivalent swap adjustments in your C# code to your byte array.

If you know you're running on Windows and don't want to worry about cross-platform support, you can assume the BinaryWriter is Little Endian (in fact, it might actually be Little Endian in Mono too even on Big Endian platforms, but I'm not sure.) If you want to be safe, you might check out a utility class by Jon Skeet that handles the necessary conversions.

C# memcpy equivalent

[edit] regarding your clarification:
As I understand, you have N objects, each has a (direct) reference to the template object. You want to write back to the template so all objects "see" these changes.

Suggestion: imlement a template broker.

class TemplateProvider
{
public MyData Template { get; set; }
}

Instead of passing the template, pass the template provider to the objects.

to simplyfy the syntax in the components, you can add a (private/internal?) property

MyData Template { get { return m_templateProvider.Template; } }
void UpdateTemplate() { m_templateProvider.Template =
(MyData) this.MemberwiseClone(); }

The template provider also simplifies locking in multithreaded scenarios.


In short, no way unless you do it yourself. But why not create a new object if you override all properties anyway?

memcopy and similar low level constructs are not supported since they undermine guarantees made by the environment.

A shallow copy for structs is made by assignment. For classes, MemberwiseClone is the method to do that - but as you say that creates a new object.

There is no built in way for that, and as it potentially breaks encapsulation it should be used with care anyway.

You could build a generic routine using reflection, but whether it works or not depends on the class itself. And yes, ti will be comparedly slow.

What's left is supporting it by a custom interface. You can provide a generic "Shallow Copy" routine that checks for the interface and uses that, and falls back to reflection when it doesn't. This makes the functionality available generally, and you can optimize the classes for which performance matters later.

Fast memcpy in C#

Option #2 is broken, since you're using the pointer after the object it points to is no longer fixed. Pointers obtained within a fixed block may only be used inside that same fixed block. And it seems like you should have used Marshal.UnsafeAddrOfPinnedArrayElement anyway (and use it only inside a fixed block pinning the array).

Have a look at Buffer.BlockCopy.

In code converted from C++ to C#, what should I use instead of memcpy?

There are oodles of way you can do this. Import the DLL if you so choose and use memcpy.

However you can also use:

  • Buffer.BlockCopy

Copies a specified number of bytes from a source array starting at a
particular offset to a destination array starting at a particular
offset.

  • Array.Copy

Copies a range of elements in one Array to another Array and performs
type casting and boxing as required.

  • Manually copy item by item as has been suggested

  • Or even faster is to use, fixed and unsafe and pointers

However if you really want speed, Array.Copy and Buffer.BlockCopy is probably your fastest and closest match.

Benchmarks

Just because I had the benchmarker open. Race your horses!

----------------------------------------------------------------------------
Operating System : Microsoft Windows 10 Pro
Version : 10.0.17134
----------------------------------------------------------------------------
CPU Name : Intel(R) Core(TM) i7-3770K CPU @ 3.50GHz
Description : Intel64 Family 6 Model 58 Stepping 9
Cores (Threads) : 4 (8) : Architecture : x64
Clock Speed : 3901 MHz : Bus Speed : 100 MHz
L2Cache : 1 MB : L3Cache : 8 MB
----------------------------------------------------------------------------

Total Benchmarks : Inputs (1) * Scales (7) * Benchmarks (4) * Runs (500) = 14,000

Results 1

----------------------------------------------------------------------------
Mode : Release (64Bit)
Test Framework : .NET Framework 4.7.1 (CLR 4.0.30319.42000)
----------------------------------------------------------------------------

Total Benchmarks : Inputs (1) * Scales (7) * Benchmarks (4) * Runs (500) = 14,000

NET Framework 4.7.1

--- Standard input --------------------------------------------------------------------
| Value | Average | Fastest | Cycles | Garbage | Test | Gain |
--- Scale 10 ----------------------------------------------------------- Time 0.994 ---
| ArrayCopy | 0.005 ms | 0.004 ms | 23.016 K | 7.927 KB | N/A | 14.98 % |
| ElemCopy | 0.006 ms | 0.004 ms | 23.591 K | 8.000 KB | N/A | 12.08 % |
| ElemCopy Unsafe | 0.006 ms | 0.004 ms | 26.426 K | 7.915 KB | N/A | 0.77 % |
| BlockCopy | 0.006 ms | 0.004 ms | 26.295 K | 7.836 KB | Base | 0.00 % |
--- Scale 100 ---------------------------------------------------------- Time 1.124 ---
| ArrayCopy | 0.005 ms | 0.004 ms | 20.581 K | 7.937 KB | N/A | 1.60 % |
| BlockCopy | 0.005 ms | 0.004 ms | 20.915 K | 8.000 KB | Base | 0.00 % |
| ElemCopy | 0.005 ms | 0.004 ms | 21.836 K | 8.000 KB | N/A | -4.15 % |
| ElemCopy Unsafe | 0.005 ms | 0.004 ms | 22.357 K | 7.970 KB | N/A | -10.85 % |
--- Scale 1,000 -------------------------------------------------------- Time 1.322 ---
| ArrayCopy | 0.005 ms | 0.005 ms | 23.106 K | 8.000 KB | N/A | 6.31 % |
| ElemCopy Unsafe | 0.006 ms | 0.005 ms | 24.075 K | 8.000 KB | N/A | 1.41 % |
| ElemCopy | 0.006 ms | 0.005 ms | 24.392 K | 8.000 KB | N/A | 0.46 % |
| BlockCopy | 0.006 ms | 0.004 ms | 24.766 K | 8.015 KB | Base | 0.00 % |
--- Scale 10,000 ------------------------------------------------------- Time 1.727 ---
| BlockCopy | 0.013 ms | 0.009 ms | 51.749 K | 86.172 KB | Base | 0.00 % |
| ArrayCopy | 0.016 ms | 0.014 ms | 61.467 K | 86.172 KB | N/A | -23.61 % |
| ElemCopy Unsafe | 0.017 ms | 0.015 ms | 63.659 K | 86.172 KB | N/A | -28.22 % |
| ElemCopy | 0.019 ms | 0.016 ms | 70.479 K | 86.172 KB | N/A | -41.93 % |
--- Scale 100,000 ------------------------------------------------------ Time 1.825 ---
| BlockCopy | 0.050 ms | 0.045 ms | 178.829 K | 789.273 KB | Base | 0.00 % |
| ArrayCopy | 0.101 ms | 0.089 ms | 357.518 K | 789.273 KB | N/A | -102.24 % |
| ElemCopy Unsafe | 0.121 ms | 0.108 ms | 428.179 K | 789.273 KB | N/A | -143.35 % |
| ElemCopy | 0.133 ms | 0.118 ms | 469.168 K | 789.273 KB | N/A | -166.41 % |
--- Scale 1,000,000 ---------------------------------------------------- Time 4.946 ---
| BlockCopy | 0.494 ms | 0.409 ms | 1.730 M | 7.637 MB | Base | 0.00 % |
| ElemCopy Unsafe | 1.336 ms | 1.164 ms | 4.674 M | 7.637 MB | N/A | -170.59 % |
| ArrayCopy | 1.478 ms | 1.298 ms | 5.169 M | 7.637 MB | N/A | -199.40 % |
| ElemCopy | 1.910 ms | 1.607 ms | 6.675 M | 7.637 MB | N/A | -286.95 % |
--- Scale 10,000,000 -------------------------------------------------- Time 31.376 ---
| BlockCopy | 5.408 ms | 4.589 ms | 18.896 M | 76.302 MB | Base | 0.00 % |
| ElemCopy Unsafe | 43.981 ms | 35.344 ms | 153.137 M | 76.302 MB | N/A | -713.21 % |
| ElemCopy | 46.318 ms | 37.623 ms | 161.225 M | 76.302 MB | N/A | -756.43 % |
| ArrayCopy | 48.171 ms | 38.471 ms | 167.548 M | 76.302 MB | N/A | -790.69 % |
---------------------------------------------------------------------------------------

Results 2

----------------------------------------------------------------------------
Mode : Release (64Bit)
Test Framework : .Net Core 2.0 (CLR 4.0.30319.42000)
----------------------------------------------------------------------------

Total Benchmarks : Inputs (1) * Scales (7) * Benchmarks (4) * Runs (500) = 14,000

.Net Core 2.0

Test 1

--- Standard input ----------------------------------------------------------------------
| Value | Average | Fastest | Cycles | Garbage | Test | Gain |
--- Scale 10 ------------------------------------------------------------- Time 1.221 ---
| ElemCopy Unsafe | 0.006 ms | 0.003 ms | 23.940 K | 8.000 KB | N/A | 13.53 % |
| BlockCopy | 0.007 ms | 0.004 ms | 27.573 K | 7.923 KB | Base | 0.00 % |
| ArrayCopy | 0.007 ms | 0.004 ms | 28.341 K | 7.914 KB | N/A | -5.98 % |
| ElemCopy | 0.007 ms | 0.003 ms | 28.939 K | 7.914 KB | N/A | -6.12 % |
--- Scale 100 ------------------------------------------------------------ Time 1.333 ---
| BlockCopy | 0.005 ms | 0.004 ms | 19.855 K | 7.970 KB | Base | 0.00 % |
| ElemCopy | 0.005 ms | 0.004 ms | 22.061 K | 7.950 KB | N/A | -11.44 % |
| ArrayCopy | 0.005 ms | 0.004 ms | 22.793 K | 8.000 KB | N/A | -15.94 % |
| ElemCopy Unsafe | 0.006 ms | 0.004 ms | 23.715 K | 7.999 KB | N/A | -21.65 % |
--- Scale 1,000 ---------------------------------------------------------- Time 1.464 ---
| BlockCopy | 0.005 ms | 0.004 ms | 21.045 K | 8.001 KB | Base | 0.00 % |
| ElemCopy Unsafe | 0.005 ms | 0.004 ms | 21.731 K | 8.016 KB | N/A | -5.53 % |
| ElemCopy | 0.006 ms | 0.004 ms | 24.120 K | 8.000 KB | N/A | -17.49 % |
| ArrayCopy | 0.006 ms | 0.004 ms | 27.113 K | 8.013 KB | N/A | -31.62 % |
--- Scale 10,000 --------------------------------------------------------- Time 1.846 ---
| BlockCopy | 0.010 ms | 0.008 ms | 37.962 K | 86.172 KB | Base | 0.00 % |
| ArrayCopy | 0.018 ms | 0.014 ms | 67.134 K | 86.172 KB | N/A | -83.72 % |
| ElemCopy Unsafe | 0.019 ms | 0.014 ms | 72.097 K | 86.172 KB | N/A | -99.35 % |
| ElemCopy | 0.021 ms | 0.016 ms | 77.657 K | 86.172 KB | N/A | -113.22 % |
--- Scale 100,000 -------------------------------------------------------- Time 2.880 ---
| BlockCopy | 0.027 ms | 0.020 ms | 100.355 K | 789.305 KB | Base | 0.00 % |
| ArrayCopy | 0.385 ms | 0.289 ms | 1.346 M | 789.305 KB | N/A | -1,305.09 % |
| ElemCopy Unsafe | 0.404 ms | 0.280 ms | 1.414 M | 789.305 KB | N/A | -1,374.97 % |
| ElemCopy | 0.408 ms | 0.322 ms | 1.424 M | 789.305 KB | N/A | -1,389.61 % |
--- Scale 1,000,000 ----------------------------------------------------- Time 11.892 ---
| BlockCopy | 0.632 ms | 0.415 ms | 2.198 M | 7.637 MB | Base | 0.00 % |
| ElemCopy | 4.645 ms | 3.347 ms | 16.159 M | 7.637 MB | N/A | -635.36 % |
| ArrayCopy | 4.706 ms | 3.684 ms | 16.376 M | 7.637 MB | N/A | -645.01 % |
| ElemCopy Unsafe | 4.774 ms | 3.467 ms | 16.568 M | 7.637 MB | N/A | -655.66 % |
--- Scale 10,000,000 ---------------------------------------------------- Time 35.806 ---
| BlockCopy | 6.116 ms | 4.635 ms | 21.294 M | 76.302 MB | Base | 0.00 % |
| ElemCopy Unsafe | 44.132 ms | 35.039 ms | 153.807 M | 76.302 MB | N/A | -621.63 % |
| ArrayCopy | 49.990 ms | 40.360 ms | 173.860 M | 76.302 MB | N/A | -717.41 % |
| ElemCopy | 50.552 ms | 38.044 ms | 175.432 M | 76.302 MB | N/A | -726.60 % |
-----------------------------------------------------------------------------------------

Input

public static double[] ArrayOfDouble(int scale)
{
return Enumerable.Range(1, scale)
.Select(x =>_rand.NextDouble())
.ToArray();
}

Code

[Test("BlockCopy", "", true)]
public double[] Test1(double[] input, int scale)
{
var result = new double[scale];
Buffer.BlockCopy(input, 0, result, 0, input.Length);
return result;
}

[Test("ArrayCopy", "", false)]
public double[] Test2(double[] input, int scale)
{
var result = new double[scale];
Array.Copy(input, 0, result, 0, input.Length);
return result;
}

[Test("ElemCopy", "", false)]
public double[] Test3(double[] input, int scale)
{
var result = new double[scale];
for (var i=0; i <input.Length; i++)
result[i] = input[i];
return result;
}

[Test("ElemCopy Unsafe", "", false)]
unsafe public double[] Test4(double[] input, int scale)
{
var result = new double[scale];
fixed(double* pInput = input, pResult = result)
for (var i=0; i <input.Length; i++)
*(pResult+i) = *(pResult+i);
return result;
}

Summary

This should be taken with a grain of salt, and any real tests should be done on your own system. However it is a good estimate of what I'm getting when scaled.

In this case with doubles BlockCopy performs really well, ArrayCopy falls off at high scales, I'm not sure why, Unsafe always has performance benefits in these kind of things, but can't match the dedicated BCL Methods.

What is the difference between various memory copy functions in NetCore?

I have found out that following methods are heavily optimized based on the data length you are trying to copy.

If source and destination memory overlaps they will use memmove (aligning and moving memory), otherwise bulkcopy (copying data in chunks)

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void __BulkMoveWithWriteBarrier(ref byte destination, ref byte source, nuint byteCount);

[DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
private static extern unsafe void __Memmove(byte* dest, byte* src, nuint len);

Array.Copy, Buffer.BlockCopy, Buffer.MemoryCopy, Span.CopyTo, Span.TryCopyTo are calling a generic Buffer.Memmove that will decide which one of the two to use.

System.Buffer.MemoryCopy seems to use a custom implementation
instead of calling the native memcpy function or using the cpblk
instruction (and it seems to dynamically switch between a (custom)
memcpy and a QCall memmove).

Some answers that helped:

How is Array.Copy implemented in C#?

Where is the implementation of "_Memmove" in the core library souce code

Easy way to implement memcpy() like CopyTo in C#

I think the serialization/deserialization is the "easiest" way to do this. Additionaly, there's a faster way to do it, using pinned handles.

You could use Marshal & GCHandle like such (from this link ):

public static object RawDeserializeEx( byte[] rawdatas, Type anytype ) 
{
int rawsize = Marshal.SizeOf( anytype );
if( rawsize > rawdatas.Length )
return null;
GCHandle handle = GCHandle.Alloc( rawdatas, GCHandleType.Pinned );
IntPtr buffer = handle.AddrOfPinnedObject();
object retobj = Marshal.PtrToStructure( buffer, anytype );
handle.Free();
return retobj;
}

public static byte[] RawSerializeEx( object anything )
{
int rawsize = Marshal.SizeOf( anything );
byte[] rawdatas = new byte[ rawsize ];
GCHandle handle = GCHandle.Alloc( rawdatas, GCHandleType.Pinned );
IntPtr buffer = handle.AddrOfPinnedObject();
Marshal.StructureToPtr( anything, buffer, false );
handle.Free();
return rawdatas;
}


Related Topics



Leave a reply



Submit