Equivalent of memset in C# unsafe code
Well, there is... memset. Why settle for a replacement when you can p/invoke the real thing?
[DllImport("msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static extern IntPtr MemSet(IntPtr dest, int c, IntPtr count);
Taken from pinvoke.net
edit
As @Hans rightfully mentions in the OP comments, this is useless if you don't already know the size of *buffer.
Passing byte[] as IntPtr by PInvoke to memset
Your code is fine and will work correctly.
It would be perfectly reasonable, and much clearer in my view, to avoid unsafe
and declare the parameter to memset
to be byte[]
. I'd declare it like this:
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr memset(byte[] dest, int c, IntPtr count);
Note that the final parameter is size_t
which is pointer sized.
I also do wonder why you are opting to do this at all in unmanaged code, but presumably you have your reasons.
How to quickly zero out an array?
Try Array.Clear():
Sets a range of elements in the Array
to zero, tofalse
, or to
null
(Nothing in Visual Basic), depending
on the element type.
c# cannot execute c++ dll with memset inside
..., ref char result,int max_result_size,ref int realResultSize
The char*
parameter is ambiguous in C and C++. Could mean a reference to a single char (ref char in C#) or a reference to an array (char[] in C#). That doesn't matter much in those languages, although you can certainly get it wrong the exact same way you got it wrong here, but it makes a big, big difference in C#. You get it wrong in C by passing a char& instead of a char[]& and the memset() call will corrupt the stack of the caller. Same thing happens here.
Since the pinvoke marshaller doesn't know that it should actually pass an array reference, and the char
type is not compatible with C code since it is 2 bytes in C# and 1 byte in C, the marshaller makes a copy of the single char to convert it to byte. Your memset() call now corrupts the memory allocated by the pinvoke marshaller for that single byte. Outcome is quite unpredictable, you only get an AVE if you're lucky.
Something else it does not know is that it must copy the array back. Beyond not knowing it is an array, it also doesn't know its length. And you have to ask for it, by default the pinvoke marshaller doesn't copy arrays back to avoid the cost of doing so.
Telling the pinvoke marshaller that it is an array that needs to be copied back looks like this:
..., [Out][MarshalAs(UnmanagedType.LPArray, SizeParamIndex(6)] char[] result
The [Out] attribute asks for array elements to be copied back, the SizeParamIndex property says where to look when the marshaller needs to know how many elements need to be copied.
It is both simpler and more efficient by not forcing the pinvoke marshaller to convert the array elements:
..., byte[] result
No longer a need to help with the [Out] and [MarshalAs] attribute. Since no conversion is required anymore, the pinvoke marshaller can simply pin the array and pass a pointer to its first element. Your C code now writes directly to the GC heap storage. Good thing you have the max_result_size argument, it is very important to avoid GC heap corruption. Be sure to pass the array's Length property.
Note that the same story applies to the data
and info
parameters. Not nearly as fatal since they don't require conversion. Declare them as double[]
instead, no ref.
Fastest way in c# to clear portions of an array or move portions around
An array in c#
will already be allocated with the default value of the type, so memset
to 0
is usually irrelevant. You will never get a "dirty" array on construction.
For copy operations, you can use Array.Copy
for typed copying or Buffer.Blockcopy
for raw byte copying.
Both of these support copying from/to the same array, you just have to be careful not to provide overlapping idices.
Edit:
For clearing out data you can use Array.Clear
Initialize a byte array to a certain value, other than the default null?
For small arrays use array initialisation syntax:
var sevenItems = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
For larger arrays use a standard for
loop. This is the most readable and efficient way to do it:
var sevenThousandItems = new byte[7000];
for (int i = 0; i < sevenThousandItems.Length; i++)
{
sevenThousandItems[i] = 0x20;
}
Of course, if you need to do this a lot then you could create a helper method to help keep your code concise:
byte[] sevenItems = CreateSpecialByteArray(7);
byte[] sevenThousandItems = CreateSpecialByteArray(7000);
// ...
public static byte[] CreateSpecialByteArray(int length)
{
var arr = new byte[length];
for (int i = 0; i < arr.Length; i++)
{
arr[i] = 0x20;
}
return arr;
}
Why do ZeroMemory, etc. exist when there are memset, etc. already?
In C and C++, ZeroMemory()
and memset()
are the exact same thing.
/* In winnt.h */
#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))
/* In winbase.h */
#define ZeroMemory RtlZeroMemory
Why use ZeroMemory()
then? To make it obvious. But I prefer memset()
in C or C++ programs.
Is there a quick way of zeroing a struct in C#?
Just use:
myLunch = new ChocolateBar();
or
myLunch = default(ChocolateBar);
or
myLunch = default;
These are equivalent1, and will both end up assigning a new "all fields set to zero" value to myLunch
.
Also, ideally don't use mutable structs to start with - I typically prefer to create a struct which is immutable, but which has methods which return a new value with a particular field set differently, e.g.
ChocolateBar myLunch = new ChocolateBar().WithLength(100).WithGirth(10);
... and of course provide appropriate constructors as well:
ChocolateBar myLunch = new ChocolarBar(100, 10);
1 At least for structs declared in C#. Value types can have custom parameterless constructors in IL, but it's relatively hard to predict the circumstances in which the C# compiler will call that rather than just use the default "zero" value.
Related Topics
How to Pass Parameters to Another Process in C#
C# Wpf Navigation Between Pages (Views)
Property(With No Extra Processing) VS Public Field
How to Make Two Transparent Layer with C#
Dictionary Returning a Default Value If the Key Does Not Exist
Understanding Async/Await in C#
Display Image from Database in Asp MVC
How to Get an Oauth 2.0 Authentication Token in C#
Entity Framework Self Referencing Loop Detected
Assembly Binding Redirect: How and Why
How to Handle Click Event in Button Column in Datagridview
Difference Between Invoke and Dynamicinvoke
Can You Get the Column Names from a SQLdatareader
Which Is Better, Return Value or Out Parameter
Mail Sending with Network Credential as True in Windows Form Not Working
Apply Properties Values from One Object to Another of the Same Type Automatically