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
How Does Native Implementation of Valuetype.Gethashcode Work
Better Way to Check If a Path Is a File or a Directory
How to Call Base.Base.Method()
How to Merge Multiple PDF Files (Generated in Run Time)
Concat All Strings Inside a List<String> Using Linq
How to Write to the Console in Colour in .Net
How to Pass Values Across the Pages in ASP.NET Without Using Session
Generating Dll Assembly Dynamically at Run Time
How to Call an Async Method in Main
.Net: Simplest Way to Send Post with Data and Read Response
Centering Controls Within a Form in .Net (Winforms)
Converting Bitmapimage to Bitmap and Vice Versa
Dynamically Created Controls Losing Data After Postback
.Net Hashtable VS Dictionary - Can the Dictionary Be as Fast