Search code examples
c#bit-fields

Bit fields in C#


I have a structure which I need to populate and write to disk (several actually).

An example is:

byte-6    
bit0 - original_or_copy  
bit1 - copyright  
bit2 - data_alignment_indicator  
bit3 - PES_priority  
bit4-bit5 - PES_scrambling control.  
bit6-bit7 - reserved  

In C I might do something like the following:

struct PESHeader  {
    unsigned reserved:2;
    unsigned scrambling_control:2;
    unsigned priority:1;
    unsigned data_alignment_indicator:1;
    unsigned copyright:1;
    unsigned original_or_copy:1;
};

Is there any way to do this in C# that would enable me to access the bits using the struct dereferencing dot operator?

For a couple of structures, I can just do bit shifting wrapped in an accessor function.

I have loads of structures to handle in this way, so I'm looking for something that's easier to read and quicker to write.


Solution

  • 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