Related
I have an unmanaged code which is a type of:
unsigned long *inputParameters
I need to convert my variable inputparameters to C# type
ulong[] inputParameters
I've tried different types of conversions like
auto inputParams = *((unsigned long*)inputParameters)
&inputParameters
however I am getting this exception:
cannot convert argument from 'unsigned long *' to 'cli::array<unsigned __int64,1> ^'
Any types known in C# as reference types, need to be instantiated by using the gcnew keyword, arrays being no exception. Most value types are marashalled behind the scenes, so you can generally just assign managed to unmanged and vice versa without any casting or trickery. Magic, I know! There are some exception, but the compiler will let you know if there is an issue.
I am assuming that *inputParameters is a pointer list (rather than a pointer to a single value), which means that you should have a variable that contains the number of elements in the list, lets call it nElements. To do the conversion, you can do the following:
//some test data
int nElements = 10;
unsigned long *inputParameters = (unsigned long *)malloc(sizeof(unsigned long) * nElements);
for (int i = 0; i < nElements; i++)
{
*(inputParameters + i) = i * 2;//just arbitrary values
}
//now create a .NET array (lines below directly solve your question)
array<UInt64, 1>^ managedArray = gcnew array<UInt64, 1>(nElements);
for (int i = 0; i < nElements; i++)
{
tempArray[i] = *(inputParameters + i);//this will be marshalled under the hood correctly.
}
//now the array is ready to be consumed by C# code.
Here, array<UInt64, 1>^ is the C++/CLI equivalent of C#'s ulong[]. You can return managedArray to a method call from C# that expects ulong[] as the return type.
I have a byte[] object that I'm using as a data buffer.
I want to "read" it as an array of a either primitive/non-primitive structs without duplicating the byte[] data in memory.
The goal would be something like:
byte[] myBuffer;
//Buffer is populated
int[] asInts = PixieDust_ToInt(myBuffer);
MyStruct[] asMyStructs = PixieDust_ToMyStruct(myBuffer);
Is this possible? If so, how?
Is it possible? Practically, yes!
Since .NET Core 2.1, MemoryMarshal lets us do this for spans. If you are satisfied with a span instead of an array, then yes.
var intSpan = MemoryMarshal.Cast<byte, int>(myByteArray.AsSpan());
The int span will contain byteCount / 4 integers.
As for custom structs... The documentation claims to require a "primitive type" on both sides of the conversion. However, you might try using a ref struct and see that is the actual constraint. I wouldn't be surprised if it worked!
Note that ref structs are still very limiting, but the limitation makes sense for the kind of reinterpret casts that we are talking about.
Edit: Wow, the constraint is much less strict. It requires any struct, rather than a primitive. It does not even have to be a ref struct. There is only a runtime check that will throw if your struct contains a reference type anywhere in its hierarchy. That makes sense. So this should work for your custom structs as well as it does for ints. Enjoy!
You will not be able to do this. To have a MyStruct[] you'll need to actually create such an array of that type and copy the data over. You could, in theory, create your own custom type that acted as a collection, but was actually just a facade over the byte[], copying the bytes out into the struct objects as a given value was accessed, but if you end up actually accessing all of the values, this would end up copying all of the same data eventually, it would just potentially allow you to defer it a bit and may be helpful if you only actually use a small number of the values.
Consider class System.BitConverter
This class has functions to reinterpret the bytes starting at a given index as an Int32, Int64, Double, Boolean, etc. and back from those types into a sequence of bytes.
Example:
int32 x = 0x12345678;
var xBytes = BitConverter.GetBytes(x);
// bytes is a byte array with length 4: 0x78; 0x56; 0x34; 0x12
var backToInt32 = BitConverter.ToInt32(xBytes, 0);
Or if your array contains mixed data:
double d = 3.1415;
int16 n = 42;
Bool b = true;
Uint64 u = 0xFEDCBA9876543210;
// to array of bytes:
var dBytes = BitConverter.GetBytes(d);
var nBytes = BitConverter.GetBytes(n);
var bBytes = BitConverter.GetBytes(b);
var uBytes = BitConterter.GetBytes(u);
Byte[] myBytes = dBytes.Concat(nBytes).Concat(bBytes).Concat(uBytes).ToArray();
// startIndexes in myBytes:
int startIndexD = 0;
int startIndexN = dBytes.Count();
int startIndexB = startIndexN + nBytes.Count();
int startIndexU = startIndexB + bBytes.Count();
// back to original elements
double dRestored = Bitconverter.ToDouble(myBytes, startIndexD);
int16 nRestored = BitConverter.ToInt16(myBytes, startIndexN);
bool bRestored = BitConverter.ToBool(myBytes, startIndexB);
Uint64 uRestored = BitConverter.ToUint64(myBytes, startIndexU);
The closest you will get in order to convert a byte[] to other base-types is
Byte[] b = GetByteArray();
using(BinaryReader r = new BinaryReader(new MemoryStream(b)))
{
r.ReadInt32();
r.ReadDouble();
r.Read...();
}
There is however no simple way to convert a byte[] to any kind of object[]
Can someone please help me understand what the following code means and how it translates to C#?
unsigned int b = 100;
std::vector<bool> a (b, false);
if it was something like this:
vector<bool> a;
I'd probably just go:
List<bool> a;
Is that correct?
But I don't don't know c++, so I don't understand how a uint and a bool are being passed to a vector of type bool?
Maybe it should be something like this?
MyGenericList<int, bool> a = new MyGenericList<int, bool>(b, false);
std::vector<bool> is special, it is implemented as a bit array in C++. In other words, 1 byte stores 8 elements of the vector, the most condense possible way to create an array of bool. That's available in .NET as well, the exact equivalent declaration is:
int b = 100;
System.Collections.BitArray a = new System.Collections.BitArray(b);
If this array only ever contains 100 elements then, meh, don't bother. If it is going to contain a million then, yes, do bother.
As the other answers say, the C++ code creates something like an array or list with 100 elements, all false. The equivalent in C# would be:
var a = new bool[100];
Or if you don't need a fixed size:
var a = new List<bool>(100);
// or, if the initial capacity isn't important
var a = new List<bool>();
Since the default bool value is false, you don't need to explicitly specify it anywhere. If you wanted true (or, e.g. in a list of ints, to default to -1), you'd have to loop through it after you created it:
var a = new bool[100];
for (var i = 0; i < a.Length; i++)
a[i] = true;
std::vector<bool> a (b, false); creates a vector (an array or kind of a C# list) that is 100 bools long and initializes these bools to false.
A note: Do not use std::vector<bool>.
The first argument is the size of vector while second is it's element (see handly C++ reference). So
std::vector<bool> a(100, false);
Create vector of 100 elements, elements of which are false.
As pointed out by Scarlet std::vector<bool> is 'strange' (it does not have full C++ container interface. I'd not go so far to say 'don't use it' but it's important to know that it might behave strange - the ling above is to 'normal' vector).
I'm stuck on a seemingly trivial task and need your help.
I need to write a method with the following signature:
System.Array ToIntPtrArray(System.Array a)
where an actual argument can be an array of any pointer type (e.g. int*[], long**[], void*[,]) and returning an array of the same shape with elements of type System.IntPtr having the same numeric values as elements of an input array. The problem is that I do not understand how to extract numeric values of pointers if I do not know their types beforehand.
For example, if I knew beforehand that my argument is always of type void*[], I could write the method as follows:
unsafe IntPtr[] ToIntPtrArray(void*[] a)
{
var result = new IntPtr[a.Length];
for (int i = 0; i < a.Length; i++)
result[i] = (IntPtr) a[i];
return result;
}
But the problem is it could be not void*[], but void**[] or anything else, and the method should be able to handle all cases.
The short answer is, this cannot be done directly. The reasons are that if you pass your conversion function any of the conventional index-capable containers (System.Array, Collections.IList, ArrayList, etc.) performing the index operations will attempt to cast the result to System.Object. Pointers in C# do not derive from Object, so this will result in an SystemNotSupported or similar exception.
There are two reasonable workarounds:
Convert the pointer arrays to void pointer arrays before calling the
method.
Convert the pointer arrays to void pointer pointers before
calling the method.
The first one is rather cumbersome, as it requires duplicating the entire contents of the array with a for loop. The second option requires passing in the length of the array as it is no longer wrapped with a managed System.Array object.
Sample Code
Method:
unsafe Array ToIntPtrArray(void** a, int count)
{
IntPtr[] intPtrArray = new IntPtr[count];
for (int n = 0; n < count; n++)
intPtrArray[n] = new IntPtr(a[n]);
return intPtrArray;
}
Sample Usage (integer pointer array):
int*[] intPtrArray;
// Code that initializes the values of intPtrArray
fixed(int** ptr = &intPtrArray[0])
{
Array result = ToIntPtrArray((void**)ptr, intPtrArray.Length);
}
Sample Usage (void pointer pointer array):
void**[] voidPtrPtrArray;
// Code that initializes the values of voidPtrPtrArray
fixed(void*** ptr = &voidPtrPtrArray[0])
{
Array result = ToIntPtrArray((void**)ptr, voidPtrPtrArray.Length);
}
Sample Usage (multidimensional int pointer array):
int*[,] int2dArray;
// Code that initializes the values of int2dArray
fixed(int** ptr = &int2dArray[0,0])
{
Array result = ToIntPtrArray((void**)ptr, TotalSize(int2dArray));
Array reshaped = ReshapeArray(result,int2dArray);
}
Where TotalSize and ReshapeArray are helper functions that are written to deal with multi-dimensional arrays. For tips on how to accomplish this see: Programatically Declare Array of Arbitrary Rank.
This is a rather difficult problem. Creating an array of the proper shape isn't too bad.
unsafe System.Array ToIntPtrArray(System.Array a)
{
int[] lengths = new int[a.Rank];
int[] lowerBounds = new int[a.Rank];
for (int i = 0; i < a.Rank; ++i)
{
lengths[i] = a.GetLength(i);
lowerBounds[i] = a.GetLowerBound(i);
}
Array newArray = Array.CreateInstance(typeof (IntPtr), lengths, lowerBounds);
// The hard part is iterating over the array.
// Multiplying the lengths will give you the total number of items.
// Then we go from 0 to n-1, and create the indexes
// This loop could be combined with the loop above.
int numItems = 1;
for (int i = 0; i < a.Rank; ++i)
{
numItems *= lengths[i];
}
int[] indexes = new int[a.Rank];
for (int i = 0; i < numItems; ++i)
{
int work = i;
int inc = 1;
for (int r = a.Rank-1; r >= 0; --r)
{
int ix = work%lengths[r];
indexes[r] = lowerBounds[r] + ix;
work -= (ix*inc);
inc *= lengths[r];
}
object obj = a.GetValue(indexes);
// somehow create an IntPtr from a boxed pointer
var myPtr = new IntPtr((long) obj);
newArray.SetValue(myPtr, indexes);
}
return newArray;
}
That creates an array of the right type and shape (dimensions and length), but it has a problem. The GetValue method, which you use to get an item from the array, returns an object. And you can't cast a pointer type to an object. No way, no how. So you can't get the value from the array! If you call GetValue on an array of long*, for example, you'll get "type not supported."
I think you need some way to copy that oddly-shaped array to a one-dimensional array of int* (or any other pointer type). Then you could directly index the temporary array and get the values to populate your IntPtr array.
It's an interesting chicken-and-egg problem. If you pass it as a System.Array, then you can't get items from it because there's no conversion path from object to int* (or any other pointer type). But if you pass it as a pointer type (i.e. int**), then you can't get the shape of the thing.
I suppose you could write it as:
unsafe System.Array ToIntPtrArray(System.Array a, void** aAsPtr)
You then have the System.Array metadata and the actual data in a form that you can use.
Even though the question has been answered well, I feel the need to leave a note/warning to future readers.
The CLR is designed to keep you safe, or at least as safe as possible. It accomplishes this with (among other things) type safety and abstracting memory operations. While you can turn some of these protections off with the unsafe block, some protections are hardcoded into the compiler/runtime. In order to circumvent this additional hurdle, one must resort to some hackey, and possibly slow, code. While these methods work, experience has taught me that doing such things leads to problems down the road, whether it be a change in the runtime, a future programmer needing to modify that segment of code, or you yourself needing to do something else with those pointers later on in the code.
At this point, I would seriously consider a helper dll written in Managed C++ to handle the "raw pointer" side of things. My reasoning is that by using Unsafe, you're already throwing out many protections the CLR offers. You may find it easier to work unencumbered by any additional, baked in protections. Not to mention you can use pointers to their full extent, and then cast them back to intptr when you're done. If nothing else, you may want to look at implementing ToIntPtrArray in C++. Still pass it pointers on the C# side, but escape the CLR's oversight.
Note that I'm not saying that every time you use "unsafe" you should bust out the C++. Quite contrary - unsafe will allow you to do quite a bit - but in this instance, a C++ helper is probably something to consider.
Disclaimer: I have not done a whole lot with managed C++. It could be that I am totally wrong and the CLR would still monitor the pointers. If some more experienced soul could comment and tell me either way, It'd be much appreciated.
These are example from a c# book that I am reading just having a little trouble grasping what this example is actually doing would like an explanation to help me further understand what is happening here.
//creates and initialzes firstArray
int[] firstArray = { 1, 2, 3 };
//Copy the reference in variable firstArray and assign it to firstarraycopy
int[] firstArrayCopy = firstArray;
Console.WriteLine("Test passing firstArray reference by value");
Console.Write("\nContents of firstArray " +
"Before calling FirstDouble:\n\t");
//display contents of firstArray with forloop using counter
for (int i = 0; i < firstArray.Length; i++)
Console.Write("{0} ", firstArray[i]);
//pass variable firstArray by value to FirstDouble
FirstDouble(firstArray);
Console.Write("\n\nContents of firstArray after " +
"calling FirstDouble\n\t");
//display contents of firstArray
for (int i = 0; i < firstArray.Length; i++)
Console.Write("{0} ", firstArray[i]);
// test whether reference was changed by FirstDouble
if (firstArray == firstArrayCopy)
Console.WriteLine(
"\n\nThe references refer to the same array");
else
Console.WriteLine(
"\n\nThe references refer to different arrays");
//method firstdouble with a parameter array
public static void FirstDouble(int[] array)
{
//double each elements value
for (int i = 0; i < array.Length; i++)
array[i] *= 2;
//create new object and assign its reference to array
array = new int[] { 11, 12, 13 };
Basically there is the code what I would like to know is that the book is saying if the array is passed by value than the original caller does not get modified by the method(from what i understand). So towards the end of method FirstDouble they try and assign local variable array to a new set of elements which fails and the new values of the original caller when displayed are 2,4,6.
Now my confusion is how did the for loop in method FirstDouble modify the original caller firstArray to 2,4,6 if it was passed by value. I thought the value should remain 1,2,3.
Thanks in advance
The key to understanding this is to know the difference between a value type and a reference type.
For example, consider a typical value type, int.
int a = 1;
int b = a;
a++;
After this code has executed, a has the value 2, and b has the value 1. Because int is a value type, b = a takes a copy of the value of a.
Now consider a class:
MyClass a = new MyClass();
a.MyProperty = 1;
MyClass b = a;
a.MyProperty = 2;
Because classes are reference types, b = a merely assigns the reference rather than the value. So b and a both refer to the same object. Hence, after a.MyProperty = 2 executes, b.MyProperty == 2 since a and b refer to the same object.
Considering the code in your question, an array is a reference type and so for this function:
public static void FirstDouble(int[] array)
the variable array is actually a reference, because int[] is a reference type. So array is a reference that is passed by value.
Thus, modifications made to array inside the function are actually applied to the int[] object to which array refers. And so those modifications are visible to all references that refer to that same object. And that includes the reference that the caller holds.
Now, if we look at the implementation of this function:
public static void FirstDouble(int[] array)
{
//double each elements value
for (int i = 0; i < array.Length; i++)
array[i] *= 2;
//create new object and assign its reference to array
array = new int[] { 11, 12, 13 };
}
there is one further complication. The for loop simply doubles each element of the int[] that is passed to the function. That's the modification that the caller sees. The second part is the assignment of a new int[] object to the local variable array. This is not visible to the caller because all it does is to change the target of the reference array. And since the reference array is passed by value, the caller does not see that new object.
If the function had been declared like this:
public static void FirstDouble(ref int[] array)
then the reference array would have been passed by reference and the caller would see the newly created object { 11, 12, 13 } when the function returned.
What a confusing use of terms!
To clarify,
for a method foo(int[] myArray), "passing a reference (object) by value" actually means "passing a copy of the object's address (reference)". The value of this 'copy', ie. myArray, is initially the Address (reference) of the original object, meaning it points to the original object. Hence, any change to the content pointed to by myArray will affect the content of the original object.
However, since the 'value' of myArray itself is a copy, any change to this 'value' will not affect the original object nor its contents.
for a method foo(ref int[] refArray), "passing a reference (object) by reference" means "passing the object's address (reference) itself (not a copy)". That means refArray is actually the original address of the object itself, not a copy. Hence, any change to the 'value' of refArray, or the content pointed to by refArray is a direct change on the original object itself.
All method parameters are passed by value unless you specifically see ref or out.
Arrays are reference types. This means that you're passing a reference by value.
The reference itself is only changed when you assign a new array to it, which is why those assignments aren't reflected in the caller. When you de-reference the object (the array here) and modify the underlying value you aren't changing the variable, just what it points to. This change will be "seen" by the caller as well, even though the variable (i.e. what it points to) remains constant.
idea for you all there with knowledge of .net open sources to implement the logics;
//Sample Code, Illustration;
Method1(params dynamic[] var1) {
var1[0]=new dynamic[3] { 1,2,3 }
}
the var1 is not specified or cannot be ref ?
a usage scenario would be ...
//Sample Code, Illustration;
dynamic[] test = new dynamic[];
Method1( ref test,x,x,x,x );
System.Windows.MessageBox.Show( test[2].ToString() );
to indicate ref only when, not being a parameter specific;
and a ref to array items;
//result is IndexOutOfBounds;
this is only a illustrationm it can be done by returning a array and use like:
test = Method1( test,... );
instead of :
Method1( ref test,x,x,..., ref test[x], ref test2, ... );