0

I want to pack bit fields and use a single variable for this, in my example p. I want to get 16 bit PESHeader structure. But I could not figure out how to access and pack the bits using reflection. It will be very helpful, if you offer me better methods than using reflection.

I used the example at Bit fields in C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            PESHeader p = new PESHeader();
            PES1Header p1 = new PES1Header();


            p1.a1 = 3;
            p1.a2 = 2;
            p1.a3 = 1;

            p.b1 = p1;
            p.b2.s2 = 1;

            long l = PrimitiveConversion.ToLong(p1);

            long l2 = PrimitiveConversion.ToLong(p);

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

            Console.WriteLine();

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

            Console.WriteLine();            
        }
    }
}


[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 PES1Header
{
    [BitfieldLength(2)]
    public byte a1;
    [BitfieldLength(2)]
    public byte a2;
    [BitfieldLength(4)]
    public byte a3;
};

struct PES2Header
{
    [BitfieldLength(4)]
    public byte s1;
    [BitfieldLength(4)]
    public byte s2;
};

struct PESHeader
{
    public PES1Header b1;
    public PES2Header b2;
};
Rand Random
  • 7,300
  • 10
  • 40
  • 88
electro103
  • 147
  • 6
  • 1
    Did you check the [BitArray](https://msdn.microsoft.com/en-us/library/system.collections.bitarray(v=vs.110).aspx)? – Jeroen van Langen Feb 06 '18 at 15:26
  • As it looks to me like you want to recreate a predefined Header structure which usually follows a quite rigid structure, have you thought about using a type holding [Enum Flags](https://msdn.microsoft.com/library/system.flagsattribute(v=vs.110).aspx) and simply concatenate the resulting Enum-Numbers in binary-form? – Jirajha Feb 06 '18 at 15:39

1 Answers1

0

You could use an enum with the [Flags] attribute:

[Flags]
enum Something
{
    None = 0,
    RequestTimeout = 1 << 0,
    CorruptedResponse = 1 << 2,
    NuclearApocalypse = 1 << 3
}

To assign:

Something s = CorruptedResponse | RequestTimeout; // both flags set

To check for a flag:

if (s.HasFlag(NuclearApocalypse))

You can still use bitwise operations to check for multiple values.

Glasses2C_Sharp
  • 149
  • 2
  • 8