简体   繁体   中英

C# StructLayout Pack=?? for use with bool values

In C#, I am creating multiple different structs that contain 16 variables of type bool. I will have several different of these structs that will then be combined with other data types into more complex structs. I am needing to have them treated as being 2 bytes in length. In the code below, a variable created of type CtrlWord1 will give a length of 64 when I do a Marshal.SizeOf regardless of whether it is created with a Pack value of 0, 1 or 2.

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CtrlWord1
{
    public bool a1;
    public bool a2;
    public bool a3;
    public bool a4;
    public bool a5;
    public bool a6;
    public bool a7;
    public bool a8;
    public bool b1;
    public bool b2;
    public bool b3;
    public bool b4;
    public bool c1;
    public bool c2;
    public bool c3;
    public bool c4;
}

Although the bool type in C# is only 1 byte in size ( sizeof(bool) == 1 ), the CLR defaults to marshalling it as the unmanaged BOOL type. This is the size you get when you call Marshal.SizeOf .

BOOL is a typedef in the Windows SDK headers for an int , which is 4 bytes in size. Why? Because these headers were written for the C language at a time that this language did not have a first-class Boolean type. It does now, but the decisions are fixed in stone for backwards-compatibility reasons. The CLR marshals bool types this way in order to be compatible with Windows API functions that use BOOL values, since interop with the Windows API is the most common usage of P/Invoke. (The same reason that the default calling convention for P/Invoke signatures is stdcall instead of cdecl.)

To tell the CLR to treat your bool s as 1-byte bools, rather than 4-byte BOOL s, use the MarshalAs attribute . Unfortunately, you have to use it 16 times:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CtrlWord1
{
    [MarshalAs(UnmanagedType.I1)]  // marshal as a 1-byte signed int, not a 4-byte BOOL
    public bool a1;

    // etc.
}

This will ensure that your struct is only 16 bytes.

However, there's no magic attribute to generate a bitfield. You'll have to create and manage this yourself using the Int32 type. Or use the BitArray type.

Glorin Oakenfoot said it much better than I could , so I will just quote him

Packing/layout is done at the byte level. That means a bool will never take less than a byte relying purely on packing. You'll have to do something a little more involved, such as use two private byte fields and multiple properties which refer to the appropriate bits within those bytes.

Here is a implementation of that, each item you increment the right hand side of the 1 << _ to move to the next bit field.

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CtrlWord1
{
    private Int16 _backingField;

    private void SetBitfield(Int16 mask, bool value)
    {
        if (value)
        {
            _backingField = (Int16)(_backingField | mask);
        }
        else
        {
            _backingField = (Int16)(_backingField & ~mask);
        }
    }

    private bool GetBitfield(Int16 mask)
    {
        return (_backingField & A1_MASK) != 0;
    }

    private const Int16 A1_MASK = 1 << 0;
    public bool a1
    {
        get { return GetBitfield(A1_MASK); }
        set { SetBitfield(A1_MASK, value); }
    }


    private const Int16 A2_MASK = 1 << 1;
    public bool a2
    {
        get { return GetBitfield(A2_MASK); }
        set { SetBitfield(A2_MASK, value); }
    }

    private const Int16 A3_MASK = 1 << 2;
    public bool a3
    {
        get { return GetBitfield(A3_MASK); }
        set { SetBitfield(A3_MASK, value); }
    }

    private const Int16 A4_MASK = 1 << 3;
    public bool a4
    {
        get { return GetBitfield(A4_MASK); }
        set { SetBitfield(A4_MASK, value); }
    }

    //And so on
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM