Memory layout of C# array of struct - c#

In C, if I have the following struct Data:
struct __attribute__((__packed__)) Data
{
double x;
int y;
};
And then create an array named val of this struct:
Data val[3];
All values stored in val (i.e. val[0].x, val[0].y, val[1].x, val[1].y, val[2].x and val[2].y are contiguous in memory.
Now, when having the following struct in C#:
[StructLayout(LayoutKind.Sequential, Pack=0)]
struct Data
{
public double x;
public int y;
}
And then create an array named val of this struct:
Data val[3];
I would expect that all values stored in val are contiguous in memory, which they are not (based on the tests that I have conducted). In details, val[0].x and val[0].y are both contiguous, but they are not contiguous with val[1] (which, in turn, is not contiguous with val[2]).
My question is: in C#, how can I create a variable (that is an array) of a certain struct that all its elements and members are contiguous in memory?

Just to try it, I made a very simple project: using Pack=1 seems to pack perfectly fine to the smallest byte.
Reproducing code (on a console app):
[StructLayout(LayoutKind.Sequential, Pack=1)]
struct Data
{
public double x;
public int y;
}
class Program {
static void Main()
{
Data[] val = new Data[3] {
new Data { x = 0, y = 0 },
new Data { x = 1, y = 1 },
new Data { x = 2, y = 2 },
};
for(var i = 0; i < 3; i++)
{
Console.WriteLine("data[" + i + "].x = " + BitConverter.ToString(BitConverter.GetBytes(val[i].x)));
Console.WriteLine("data[" + i + "].y = " + BitConverter.ToString(BitConverter.GetBytes(val[i].y)));
}
unsafe {
fixed (Data *p = &val[0])
{
byte *c = (byte *)p;
for(var j = 0; j < 3; j++)
{
for(var i = 0; i < Marshal.SizeOf<double>(); i++, c++)
{
if(i!=0) Console.Write("-");
Console.Write("{0:X2}", *c);
}
Console.WriteLine();
for(var i = 0; i < Marshal.SizeOf<int>(); i++, c++)
{
if(i!=0) Console.Write("-");
Console.Write("{0:X2}", *c);
}
Console.WriteLine();
}
}
}
}
}
Output:
data[0].x = 00-00-00-00-00-00-00-00
data[0].y = 00-00-00-00
data[1].x = 00-00-00-00-00-00-F0-3F
data[1].y = 01-00-00-00
data[2].x = 00-00-00-00-00-00-00-40
data[2].y = 02-00-00-00
00-00-00-00-00-00-00-00
00-00-00-00
00-00-00-00-00-00-F0-3F
01-00-00-00
00-00-00-00-00-00-00-40
02-00-00-00
Which looks perfectly continuous to me, unless I'm missing something

Related

How to set all array's elements into one variable in C#

For example i've got one array like
int[] array = {1,0,0,1,0}
and one int variable=0;
I want set all array's elements into variable. How can i do this?
variable=10010
In addition if we think about reverse of this situation? Variable's values set to array?
int something=10000 to int[] something={1,0,0,0,0}
Thanks for your all contribution
//==============go forwards===================
int[] array = { 1, 0, 0, 1, 0 };
int variable = 0;
for (int i = 0; i < array.Length; ++i)
{
//first element
if (i == 0)
variable = array[i];
else
{
variable *= 10;
variable += array[i];
}
}
//print resualts
Console.WriteLine(variable);
//===================go backwards===============
int variable2 = 10010;
//convert it into a char array
string value = variable2+"";
//set the array length based on the size
int[] reverse = new int[value.Length];
//loop
for (int i = 0; i < value.Length; ++i)
{
//grab the number from a char value and push it into the array
reverse[i] = (int)Char.GetNumericValue(value[i]);
}
//print out
for(int i = 0; i <reverse.Length;++i)
{
Console.WriteLine("[" + i + "] = " + reverse[i]);
}
Yet another way to do this, but not as compact as others. This approach demonstrates bit-wise operations to construct an int from the array of 0's and 1's.
class Program
{
// converts array of 0's and 1's to an int, and assumes big endian format.
static int bitArrayToInt(int[] bit_array)
{
int rc = 0;
for (int i = 0; i < bit_array.Length; i++)
{
rc <<= 1; // bit shift left
rc |= bit_array[i]; // set LSB according to arr[i].
}
return rc;
}
static void Main(string[] args)
{
int[] array = { 1, 0, 0, 1, 0 };
int rc = bitArrayToInt(array);
System.Console.WriteLine("{0} = {1} binary",rc, Convert.ToString(rc, 2));
System.Console.ReadLine();
}
}
There's a huge number of choices on how to approach the problem.
Shortest quickest method I could think of.
byte[] array = { 1, 0, 1, 0, 0 };
string temp = "";
int result = 0;
for (int i = 0; i < array.Length; i++)
temp += array[i].ToString();
result = Convert.ToInt32(temp);
I'm on my phone here, so bear with me, but if performance isn't an issue then how about something like:
int.Parse(string.Join(string.Empty, array.Select(d => d.ToString()));
Obviously you'll need some error handling around the parsing for overflows, invalid characters, etc.

C# - Converting String array to sbyte** (String[] to sbyte**)

XFunction is a CLI to managed C++ code (wrapper).
I want to use XFunction(int,sbyte**) in my C# Project and convert String array to sbyte**.
sbyte[][] sbytes = new sbyte[7][];
for (int argCounter = 0; argCounter < 7 ; argCounter++)
{
//get the byte array
byte[] bytes = Encoding.ASCII.GetBytes(argument[argCounter]);
//convert it to sbyte array
sbytes[argCounter] = new sbyte[bytes.Length];
for (int i = 0; i < bytes.Length; i++)
sbytes[argCounter][i] = (sbyte)bytes[i];
}
when I calling:
XFunction(7,sbytes);
and buid, generate this error:
The best overloaded method match for 'XFunction(int, sbyte**)' has
some invalid arguments Argument 2: cannot convert from 'sbyte[][]'
to 'sbyte**'
How can I fixed this error???
You need to use fixed to get pointer to your array and to prevent garbage collection from relocating your variable.
You may want to do something like this:
public static unsafe void CallXFunction(int a, sbyte[][] array)
{
var pointerArray = new sbyte*[array.Length];
// Recursive fixing so that whole array get's pinned at same time
// (never use fixed pointer outside of fixed{} statement)
Action<int> fixArray = null;
fixArray = (pos) =>
{
fixed (sbyte* ptr = array[pos])
{
pointerArray[pos] = ptr;
if (pos <= (array.Length - 2))
{
fixArray(pos + 1);
}
else
{
fixed (sbyte** pointer = pointerArray)
{
XFunction(a, pointer);
}
}
}
};
fixArray(0);
}
it solved by:
sbyte[][] sbytes = new sbyte[6][];
for (int argCounter = 0; argCounter < 6 ; argCounter++)
{
get the byte array
byte[] bytes = Encoding.ASCII.GetBytes(argument[argCounter]);
convert it to sbyte array1
sbytes[argCounter] = new sbyte[bytes.Length];
for (int i = 0; i < bytes.Length; i++)
sbytes[argCounter][i] = (sbyte)bytes[i];
}
unsafe
{
fixed (sbyte* junk = &sbytes[0][0])
{
sbyte*[] arrayofptr = new sbyte*[sbytes.Length];
for (int i = 0; i < sbytes.Length; i++)
{
fixed (sbyte* ptr = &sbytes[i][0])
{
arrayofptr[i] = ptr;
}
}
fixed (sbyte** ptrptr = &arrayofptr[0])
{
XFunction(7, ptrptr);
}
}
}

Converting Suprema Biostar C++ code to C#

I got the Biostation T2 from Suprema, they provided a wrapped Dll made with C#, they also provide example using: VB6, VB.net, C++ and C#.Most of the documentation is in C++ and am having a hard time trying to convert that logic to C#.I am unable to enroll a user using the below functions in the pastie.Mainly cause am not sure if the logic in C# and C++ matches up.
See the C++ code for enrolling user and my C# attempt pastie
I get error attempted to read or write protected memory as captured here
Here ia a link of the sdk samples they provide sdk samples in vc,c#,C++
We have no way of compiling and testing your code with what you have shown us. That being said, comparing the c++ and c# side by side, I see the following inconsistencies:
The c++ has the following code:
unsigned char* templateBuf = (unsigned char*)malloc( userHeader.numOfFinger * 2 * BS_TEMPLATE_SIZE );
int bufPos = 0;
for( int i = 0; i < userHeader.numOfFinger * 2; i++ )
{
result = BS_ScanTemplate( handle, templateBuf + bufPos );
bufPos += BS_TEMPLATE_SIZE;
}
This code calls BS_ScanTemplate multiple times and stores the results sequentially in a byte array. Your code does the following:
byte[] templateBuf = new byte[userHdr.numOfFinger * 2 * BS_TEMPLATE_SIZE];
int bufPos = 0;
for (int i = 0; i < userHdr.numOfFinger * 2; i++)
{
templateBuf = new byte[userHdr.numOfFinger * 2 * BS_TEMPLATE_SIZE * bufPos];
result = BSSDK.BS_ScanTemplate(m_Handle, templateBuf);
bufPos += BS_TEMPLATE_SIZE;
}
Rather than storing the results of BS_ScanTemplate sequentially, this code throws away the results from each preceding call by reallocating the array. Perhaps you want something like:
byte[] templateBuf = new byte[userHdr.numOfFinger * 2 * BS_TEMPLATE_SIZE];
for (int i = 0, bufPos = 0; i < userHdr.numOfFinger * 2; i++)
{
byte[] singleBuf = new byte[BS_TEMPLATE_SIZE];
result = BSSDK.BS_ScanTemplate(m_Handle, singleBuf);
Array.Copy(singleBuf, 0, templateBuf, bufPos, singleBuf.Length);
bufPos += singleBuf.Length;
}
The c++ code does
for( int i = 0; i < userHeader.numOfFinger; i++ )
{
userHeader.duress[i] = 0; // no duress finger
}
The c# code does:
userHdr.duressMask = 0; // no duress finger
This is completely different.
The c++ code does:
for( int i = 0; i < userHeader.numOfFinger * 2; i++ )
{
if( i % 2 == 0 )
{
userHeader.fingerChecksum[i/2] = 0;
}
unsigned char* templateData = templateBuf + i * BS_TEMPLATE_SIZE;
for( int j = 0; j < BS_TEMPLATE_SIZE; j++ )
{
userHeader.fingerChecksum[i/2] += templateData[j];
}
}
The c# code does:
for (int i = 0; i < userHdr.numOfFinger * 2; i++)
{
if (i % 2 == 0)
{
userHdr.checksum[i / 2] = 0;
}
byte[] templateData = templateBuf;
for (int j = 0; j < 2000 - 1; j++)
{
userHdr.checksum[i / 2] += templateData[j];
}
}
As you can see the c++ code loops twice as many times as the c# code. The c# code probably should be:
for (int i = 0; i < userHdr.numOfFinger; i++)
{
if (i % 2 == 0)
{
userHdr.checksum[i / 2] = 0;
}
for (int j = 0; j < BS_TEMPLATE_SIZE; j++)
{
userHdr.checksum[i / 2] += templateBuf[i * BS_TEMPLATE_SIZE + j];
}
}
You don't show the c++ call to BS_EnrollUserBioStation2 in your pastie so it can't be compared with the c# call.
userHdr.checksum = new ushort[] { 0 }; looks wrong. Shouldn't it be something like userHdr.checksum = new ushort[userHdr.numOfFinger];
Thus I'd suggest the following:
Update BSUserHdrEx as follows:
public const int BS_MAX_NAME_LEN = 32;
public const int BS_MAX_PASSWORD_LEN = 16;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct BSUserHdrEx
{
public static BSUserHdrEx CreateDefaultBSUserHdrEx()
{
var userHdr = new BSUserHdrEx();
userHdr.name = new byte[BSSDK.BS_MAX_NAME_LEN + 1];
userHdr.department = new byte[BSSDK.BS_MAX_NAME_LEN + 1];
userHdr.password = new byte[BSSDK.BS_MAX_PASSWORD_LEN];
userHdr.checksum = new ushort[5];
return userHdr;
}
public uint ID;
public ushort reserved1;
public ushort adminLevel;
public ushort securityLevel;
public ushort statusMask; // internally used by BioStation
public uint accessGroupMask;
//char name[BS_MAX_NAME_LEN + 1];
[MarshalAs(UnmanagedType.ByValArray, SizeConst = BSSDK.BS_MAX_NAME_LEN + 1)]
public byte[] name;
//char department[BS_MAX_NAME_LEN + 1];
[MarshalAs(UnmanagedType.ByValArray, SizeConst = BSSDK.BS_MAX_NAME_LEN + 1)]
public byte[] department;
// char password[BS_MAX_PASSWORD_LEN + 1];
[MarshalAs(UnmanagedType.ByValArray, SizeConst = BSSDK.BS_MAX_PASSWORD_LEN + 1)]
public byte[] password;
public ushort numOfFinger;
public ushort duressMask;
//public ushort checksum[5];
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public ushort[] checksum;
public ushort authMode;
public ushort authLimitCount; // 0 for no limit
public ushort reserved;
public ushort timedAntiPassback; // in minutes. 0 for no limit
public uint cardID; // 0 for not used
public bool bypassCard;
public bool disabled;
public uint expireDateTime;
public uint customID; //card Custom ID
public int version; // card Info Version
public uint startDateTime;
};
Update btngetUserInfo_Click as follows:
private void btngetUserInfo_Click(object sender, EventArgs e)
{
int result;
BSSDK.BSUserHdrEx userHdr = BSSDK.BSUserHdrEx.CreateDefaultBSUserHdrEx();
userHdr.ID = 2; // 0 cannot be assigned as a user ID
userHdr.startDateTime = 0; // no check for start date
userHdr.expireDateTime = 0; // no check for expiry date
userHdr.adminLevel = BSSDK.BS_USER_NORMAL;
userHdr.securityLevel = BSSDK.BS_USER_SECURITY_DEFAULT;
userHdr.authMode = BSSDK.BS_AUTH_MODE_DISABLED; // use the authentication mode of the device
userHdr.accessGroupMask = 0xffff0201; // a member of Group 1 and Group 2;
Encoding.UTF8.GetBytes("Madman").CopyTo(userHdr.name, 0);
Encoding.UTF8.GetBytes("INC").CopyTo(userHdr.department, 0);
Encoding.UTF8.GetBytes("").CopyTo(userHdr.password, 0);
userHdr.password = Encoding.UTF8.GetBytes(""); // no password is enrolled. Password should be longer than 4 bytes.
userHdr.numOfFinger = 2;
byte[] templateBuf = new byte[userHdr.numOfFinger * 2 * BSSDK.BS_TEMPLATE_SIZE];
for (int i = 0, bufPos = 0; i < userHdr.numOfFinger * 2; i++)
{
byte[] singleBuf = new byte[BSSDK.BS_TEMPLATE_SIZE];
result = BSSDK.BS_ScanTemplate(m_Handle, singleBuf);
Array.Copy(singleBuf, 0, templateBuf, bufPos, singleBuf.Length);
bufPos += singleBuf.Length;
}
userHdr.duressMask = 0; // no duress finger
for (int i = 0; i < userHdr.numOfFinger * 2; i++)
{
if (i % 2 == 0)
{
userHdr.checksum[i / 2] = 0;
}
// byte[] templateData = templateBuf;
for (int j = 0; j < BSSDK.BS_TEMPLATE_SIZE; j++)
{
userHdr.checksum[i / 2] += templateBuf[i * BSSDK.BS_TEMPLATE_SIZE + j];
}
}
// enroll the user
result = BSSDK.BS_EnrollUserBioStation2(m_Handle, ref userHdr, templateBuf);
if (result == (int)BSSDK.BS_RET_CODE.BS_SUCCESS)
{
MessageBox.Show("user " + userHdr.name.ToString() + " enrolled");
}
update
The struct you are marshalling is BSUserHdrEx. BS_EnrollUserBioStation2 does not take this as an argument. BS_EnrollUserBioStation2 takes a BS2UserHdr as an argument (source: Page 158 of "BioStar SDK Manual V1.8.pdf".) BSUserHdrEx is an argument to BS_EnrollUserEx. (Page 129).
BS_EnrollUserEx "Enrolls a user to BioStation. Maximum 5 fingers can be enrolled per user."
BS_EnrollUserBioStation2 "Enrolls a user to BioStation T2. Maximum 10 fingers per user."
Either you need to switch to the former function, or use the latter data structure.

How to parameterize a method with a given dimension during multidimensional array iteration?

I have a function which is applied on each element of a 2D array (double[,]), but only along a given dimension.
I had to create two functions because I don't know how to pass the desired dimension to the method as a parameter. I ended up with a "vertical_foo" and a "horizontal_foo" functions, which are almost identical to each other:
private double[,] vertical_foo (double[,] a) {
int height = a.GetLength(0);
int width = a.GetLength(1);
var result = new double[height, weight];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// Here I use first ("i") dimension
int before = Math.Max(i-1, 0);
int after = Math.Min(i+1, height-1);
result[i,j] = (a[after, j] - a[before, j]) * 0.5;
}
}
return result;
}
private double[,] horizontal_foo (double[,] a) {
int height = a.GetLength(0);
int width = a.GetLength(1);
var result = new double[height, weight];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// Here I use second ("j") dimension
int before = Math.Max(j-1, 0);
int after = Math.Min(j+1, height-1);
result[i,j] = (a[i, after] - a[i, before]) * 0.5;
}
}
return result;
}
I would like to have a signature like this, where the second parameter is the dimension on which I want to apply the indexing:
private double[,] general_foo (double[,] a, int dimension) {}
Any suggestion is much welcome!
I'll take a stab at this:
private double[,] general_foo(double[,] a, int dimension)
{
var w = a.GetLength(0);
var h = a.GetLength(1);
var result = new double[w, h];
var otherDimension = 1 - dimension; // NOTE only works for 2D arrays
var otherDimensionLength = a.GetLength(otherDimension);
var dimensionLength = a.GetLength(dimension);
for (int i = 0; i < dimensionLength; i++)
{
for (int j = 0; j < otherDimensionLength; j++)
{
var setIndexes = new int[2] { j, j };
setIndexes[dimension] = i;
var beforeIndexes = new int[2] { j, j };
beforeIndexes[dimension] = Math.Max(i - 1, 0);
var afterIndexes = new int[2] { j, j };
afterIndexes[dimension] = Math.Min(i + 1, dimensionLength - 1);
var beforeValue = (double)a.GetValue(beforeIndexes);
var afterValue = (double)a.GetValue(afterIndexes);
result.SetValue((afterValue - beforeValue) * 0.5, setIndexes);
}
}
return result;
}
Here's a more generic method. It uses a few lambdas, so the it might also help you understand the use of lambdas a bit also.
// Iterates through every item in a multidementional array array
private Array MutateArray<T>(Array a, Func<T, int[], T> selector)
{
var rank = a.Rank;
var lengths = Enumerable.Range(0, a.Rank)
.Select(r => a.GetLength(r))
.ToArray(); // Get length of a in each dimension
var result = Array.CreateInstance(typeof(T), lengths);
var index = new int[a.Rank];
foreach (T item in a) // flattens array
{
result.SetValue(selector(item, index), index);
// Get next index value (I'm sure this could be improved)
for (var d = 0; d < rank; d++)
{
if (index[d] == lengths[d] - 1)
{
index[d] = 0;
}
else
{
index[d]++;
break;
}
}
}
return result;
}
// Your "foo" method
private double[,] generic_foo(double[,] a, int d)
{
var upperD = a.GetUpperBound(d);
return (double[,])MutateArray<double>(a, (x, i) =>
{
var prev = i.ToArray(); // clone
prev[d] = Math.Max(prev[d] - 1, 0);
var next = i.ToArray(); // clone
next[d] = Math.Min(next[d] + 1, upperD);
var prevVal = (double)a.GetValue(prev);
var nextVal = (double)a.GetValue(next);
return (nextVal - prevVal) * 0.5;
});
}
Would it be acceptable to do something along these lines?
int before_i = i, after_i = i;
int before_j = j, after_j = j;
switch( dimension ) {
case 0:
before_i = Math.max(i-1,0);
after_i = Math.min(i+1, width-1);
break;
case 1:
before_j = Math.max(j-1,0);
after_j = Math.min(j+1, height-1);
break;
}
result[ i, j ] = (a[after_i, after_j] - a[before_i,before_j]) * 0.5
It's not terribly pretty, but at least this way you don't need two functions.
You could pass in a delegate to extract the dimension you're interested in? (or a lambda)
Func<int[,],int,int[]> accessor here indicates the signature of a function (where the last template parameter is the return type)
private void Working()
{
DoSomething(GetRow,1);
}
So, in this example, you want the "DoSomething" worker to work on a row.
private void DoSomething(Func<int[,],int,int[]> accessor, int Idx)
{
int[,] theData = {{1,1,1,1,1},{2,2,2,2,2}};
int[] someData = accessor(theData,Idx);
}
public int[] GetRow(int[,] data,int index)
{
List<int> numbers = new List<int>();
for (int i = 0; i < data.GetLength(1); i++)
{
numbers.Add(data[index, i]);
}
return numbers.ToArray();
}
In the above example, you get a one dimensional array of 2,2,2,2,2
I'm addressing the general case of extracting a particular part of a multidimensional array here... The method/ lambda you pass in extracts the meaningful part of data...

Pass multi - dimensional array from managed code to unmanaged code

I would like to do the following:
Create three dimesinal array in c# code like this:
var myArray = new short[x,y,z];
UnanagedFunction(myArray);
Pass it to unmanaged code (c++) like this:
void UnmanagedFunction(short*** myArray)
{
short first = myArray[0][0][0];
}
UPDATED
When I try the following code I have runtime error:
Attempted to read or write to protected memory.
Thank you!!!
IntPtr Array3DToIntPtr(short[, ,] Val)
{
IntPtr ret = Marshal.AllocHGlobal((Val.GetLength(0) + Val.GetLength(1) + Val.GetLength(2)) * sizeof(short));
int offset = 0;
for (int i = 0; i < Val.GetLength(0); i++)
{
for (int j = 0; j < Val.GetLength(1); j++)
{
for (int k = 0; k < Val.GetLength(2); k++)
{
Marshal.WriteInt16(ret,offset, Val[i, j, k]);
offset += sizeof(short);
}
}
}
return ret;
}
This has been tested and it works, the only limitation is that you have to call Marshal.FreeHGlobal on the array pointer when you are done with it or you will get a memory leak, I would also suggest that you change your c++ function so that it accepts the array dimensions or you will only be able to use 3d arrays of specific size
I'm writing it in pure C#, but if you take away the unsafe static from Func, the Func should work in C/C++. Be aware that I'm note sure sure it's ok ok to write this :-)
I'm using this Indexing into arrays of arbitrary rank in C#
static unsafe void Main(string[] args) {
var myArray = new short[5, 10, 20];
short z = 0;
for (int i = 0; i < myArray.GetLength(0); i++) {
for (int j = 0; j < myArray.GetLength(1); j++) {
for (int k = 0; k < myArray.GetLength(2); k++) {
myArray[i, j, k] = z;
z++;
}
}
}
// myArray[1, 2, 3] == 243
fixed (short* ptr = myArray) {
Func(ptr, myArray.GetLength(0), myArray.GetLength(1), myArray.GetLength(2));
}
}
// To convert to C/C++ take away the static unsafe
static unsafe void Func(short* myArray, int size1, int size2, int size3) {
int x = 1, y = 2, z = 3;
int el = myArray[x * size2 * size3 + y * size3 + z]; // el == 243
}

Categories

Resources