If you are C programmer you might have noticed the existence of the bit fields in structs:
typedef struct {
int Some : 1;
int Bit : 2;
int Fields : 5;
} MyStruct;
Marshaling that code could be a pain in the ass. Before all, read Jonathan's doc, then forget about the C's sizeof, sum all the bit fields and get the value, in our sample struct we need to get that as 1 byte (1 + 2 + 5 = 8 bits = 1 byte) and then use the System.Collections.BitArray class, and convert that to their data type value. (I wrote a wrapper for doing this in a easiest way)
See the graphical explanation for understanding this.
See this sample
typedef struct { MyStruct get_mystruct (void); int some (void);/* libsample.h */
unsigned int Some : 1;
unsigned int Bit : 2;
unsigned int Fields : 5;
} MyStruct;
MyStruct get_mystruct (void) int some (void)/* libsample.c */
#include
#include "libsample.h"
{
MyStruct a;
a.Some = 0x01; //One bit: 1 - 0
a.Bit = 0x02; //Two bits: 10 - 2
a.Fields = 0x1A; //Five bits: 0001 1010 - 26
//Full return: 1101 1010
return a;
}
{
return 0;
}
Then compiling
gcc -fPIC -Wall -g -c libsample.c
gcc -g -shared -Wl,-soname,libsample.so.0 \
-o libsample.so.0.0 libsample.o -lc
/sbin/ldconfig -n .
ln -sf libsample.so.0 libsample.so
Will create the shared libraries, let's see the C# PInvoke.
public class Sample public uint GetSome () public uint GetBit () public uint GetFields () public override string ToString () [DllImport ("libsample.so")] [DllImport ("libsample.so")] public static void Main ()using System;
using System.Collections;
using System.Runtime.InteropServices;
{
[StructLayout (LayoutKind.Sequential, Size=1, Pack=4)]
public struct MyStruct
{
public byte Value;
{
BitArray bArray = new BitArray (new byte[] { Value });
BitFieldFormater a = new BitFieldFormater (bArray);
return a.GetInt (0, 1);
}
{
BitArray bArray = new BitArray (new byte[] { Value });
BitFieldFormater a = new BitFieldFormater (bArray);
return a.GetInt (1, 2);
}
{
BitArray bArray = new BitArray (new byte[] { Value });
BitFieldFormater a = new BitFieldFormater (bArray);
return a.GetInt (3, 5);
}
{
return "Some "+GetSome ()+" Bit "+GetBit ()+" Fields "+GetFields ();
}
}
public static unsafe extern MyStruct get_mystruct (); //notice the return value
public static unsafe extern int some (); //notice the return value
{
MyStruct myStruct = get_mystruct ();
System.Console.WriteLine ("some (): "+some ());
System.Console.WriteLine ("get_mystruct (): "+myStruct);
}
}
I'm using thre a class called BitFieldFormater for doing the magic:
public class BitFieldFormater public uint GetUInt (int beginBit, int bitLength) string requestedString = ""; //Getting bit values from the BitArray return (uint) BinaryToInteger (requestedString); private int BinaryToInteger (string binary) private BitArray _bitArray;using System;
using System.Collections;
{
public BitFieldFormater (BitArray bitArray)
{
_bitArray = bitArray;
}
{
if ((beginBit + bitLength) > _bitArray.Count)
throw new ArgumentException ("Begin bit plus bit length is greater than array's length");
for (int i = 0; i < bitLength; i++)
requestedString = Convert.ToInt32 (_bitArray [beginBit + i]) + requestedString;
}
{
char []elements = binary.ToCharArray ();
int result = 0, i = 0, pow = 0;
for (i = elements.Length - 1; i >= 0; i--) {
if (elements[i] == '1')
result += (int) Math.Pow (2, pow);
pow++;
}
return result;
}
}
Any bugs, please, let me know. I haven't yet tested this class with structs with byte-size greater than 1... further testing is required.
UPDATED. Feb 3rd. Lot of useless code removed... what the fuck was I thinking!?