Bit Fields in C#

Bit fields in C#

I'd probably knock together something using attributes, then a conversion class to convert suitably attributed structures to the bitfield primitives. Something like...

using System;

namespace BitfieldTest
{
[global::System.AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
sealed class BitfieldLengthAttribute : Attribute
{
uint length;

public BitfieldLengthAttribute(uint length)
{
this.length = length;
}

public uint Length { get { return length; } }
}

static class PrimitiveConversion
{
public static long ToLong<T>(T t) where T : struct
{
long r = 0;
int offset = 0;

// For every field suitably attributed with a BitfieldLength
foreach (System.Reflection.FieldInfo f in t.GetType().GetFields())
{
object[] attrs = f.GetCustomAttributes(typeof(BitfieldLengthAttribute), false);
if (attrs.Length == 1)
{
uint fieldLength = ((BitfieldLengthAttribute)attrs[0]).Length;

// Calculate a bitmask of the desired length
long mask = 0;
for (int i = 0; i < fieldLength; i++)
mask |= 1 << i;

r |= ((UInt32)f.GetValue(t) & mask) << offset;

offset += (int)fieldLength;
}
}

return r;
}
}

struct PESHeader
{
[BitfieldLength(2)]
public uint reserved;
[BitfieldLength(2)]
public uint scrambling_control;
[BitfieldLength(1)]
public uint priority;
[BitfieldLength(1)]
public uint data_alignment_indicator;
[BitfieldLength(1)]
public uint copyright;
[BitfieldLength(1)]
public uint original_or_copy;
};

public class MainClass
{
public static void Main(string[] args)
{
PESHeader p = new PESHeader();

p.reserved = 3;
p.scrambling_control = 2;
p.data_alignment_indicator = 1;

long l = PrimitiveConversion.ToLong(p);

for (int i = 63; i >= 0; i--)
{
Console.Write( ((l & (1l << i)) > 0) ? "1" : "0");
}

Console.WriteLine();

return;
}
}
}

Which produces the expected ...000101011. Of course, it needs more error checking and a slightly saner typing, but the concept is (I think) sound, reusable, and lets you knock out easily maintained structures by the dozen.

adamw

How to emulate statically the C bitfields in c#?

In the meantime, I had a similar idea @Dmitry.
I found the following solution using FieldOffset attribute.
Working well without additional code. I think it's acceptable.

[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct LiveDataBitField
{
// Where the values are effectively stored
public byte WholeField { get; private set; }

public bool VesselPresenceSw
{
get => (WholeField & 0x1) > 0;
set
{
if (value)
{
WholeField |= 1;
}
else
{
WholeField &= 0xfE;
}
}
}

public bool DrawerPresenceSw
{
get => (WholeField & 0x2) >> 1 > 0;
set
{
if (value)
{
WholeField |= (1 << 1);
}
else
{
WholeField &= 0xFD;
}
}
}
public bool PumpState
{
get => (WholeField & 0x4) >> 2 > 0;
set
{
if (value)
{
WholeField |= (1 << 2);
}
else
{
WholeField &= 0xFB;
}
}
}
public bool WaterValveState
{
get => (WholeField & 0x8) >> 3 > 0;
set
{
if (value)
{
WholeField |= (1 << 3);
}
else
{
WholeField &= 0xF7;
}
}
}
public bool SteamValveState
{
get => (WholeField & 0x10) >> 4 > 0;
set
{
if (value)
{
WholeField |= (1 << 4);
}
else
{
WholeField &= 0xEF;
}
}
}
public bool MotorDriverState
{
get => (WholeField & 0x20) >> 5 > 0;
set
{
if (value)
{
WholeField |= (1 << 5);
}
else
{
WholeField &= 0xDF;
}
}
}
}

To deserialize a byte array to struct you can use:

    public static object ReadStruct(byte[] data, Type type)
{
var pinnedPacket = GCHandle.Alloc(data, GCHandleType.Pinned);
var obj = Marshal.PtrToStructure(pinnedPacket.AddrOfPinnedObject(), type);
pinnedPacket.Free();
return obj;
}

Marshalling stucts with bit-fields in C#

There are no bit-fields in C#. So I'd go with properties that encapsulate the bit fiddling:

[StructLayout(LayoutKind.Sequential)]
public struct Rgb16 {
private readonly UInt16 raw;
public byte R{get{return (byte)((raw>>0)&0x1F);}}
public byte G{get{return (byte)((raw>>5)&0x3F);}}
public byte B{get{return (byte)((raw>>11)&0x1F);}}

public Rgb16(byte r, byte g, byte b)
{
Contract.Requires(r<0x20);
Contract.Requires(g<0x40);
Contract.Requires(b<0x20);
raw=r|g<<5|b<<11;
}
}

I've avoided adding setters, because I like immutable structs, but in principle you can add them too.

C# deserializing a binary structure with bitfields - how to do?

There is no direct support for such a structure in C#. You have to use an integral type holding all the bits and extract the fields from it afterwards.

See the solution to a very similar problem at Bit fields in C#

Perform addition on bit-fields in C#

This isn't how flags should be used. Flags are used to designate switches in a single byte, so given the binary 0000 the first bit represents an element being "on", the second a different element, etc.

So element1 is represented by: 1 = 0001, Element2: 2= 0010, Element3: 4 = 0100, etc. So to turn element 1 and element 2 on you use the binary 0011 or 3 (1+2).

FYI; this dates back to the days when computers had limited memory and being able to represent multiple states in a small number of bits was advantagous.

What you want doesn't make sense from a binary point of view, three prawns would be 0011 or switch 1 and 2. This isn't really a "state". which is what switches are for.

If you want to designate the number of prawns and perfrom addition, what's wrong with a good old fashined int?

Generic Enum for bit fields

Until the language and runtime supports static interface operators (hopefully soon!), there is no great way to support |, & and ~ as a generic. For now, if you know (and validate!) that all of your enums are of a specific data size (i.e. short in the question), then you could perhaps use Unsafe.As as a lazy way of converting things without any boxing:

public void SetFlag(T flag)
=> Unsafe.As<T, short>(ref val) |= Unsafe.As<T, short>(ref flag);

but note that use of Unsafe means any errors are on you: if you're wrong (i.e. the T is not blittable to short): very bad things could happen.



Related Topics



Leave a reply



Submit