C#StructLayout Pack = ??用于bool值

时间:2016-08-31 13:59:38

标签: c# boolean pack structlayout

在C#中,我创建了多个不同的结构,其中包含16个bool类型的变量。我将有几个不同的这些结构,然后将与其他数据类型组合成更复杂的结构。 我需要将它们视为长度为2个字节。在下面的代码中,当我执行Marshal.SizeOf时,创建的类型为CtrlWord1的变量将给出64的长度,无论它是否使用Pack值0,1或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;
}

2 个答案:

答案 0 :(得分:0)

虽然C#中的bool类型大小只有1个字节(sizeof(bool) == 1),但CLR默认将其编组为非托管BOOL类型。这是您拨打Marshal.SizeOf时获得的尺寸。

BOOL是{SDK}标头中的int的typedef,大小为4个字节。为什么?因为这些标题是在C语言编写的时候,这种语言没有第一类布尔类型。它现在确实如此,但出于向后兼容的原因,这些决定是固定的。 CLR以这种方式封送bool类型,以便与使用BOOL值的Windows API函数兼容,因为与Windows API的互操作是P / Invoke的最常见用法。 (与P / Invoke签名的默认调用约定相同的原因是stdcall而不是cdecl。)

要告诉CLR将您的bool视为1字节bool而不是4字节BOOL,请使用MarshalAs attribute。不幸的是,你必须使用它16次:

[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.
}

这将确保您的结构只有16个字节。

然而,生成位域没有神奇的属性。您必须使用Int32类型自行创建和管理。或使用BitArray类型。

答案 1 :(得分:0)

Glorin Oakenfoot said it much better than I could,所以我只引用他

  

打包/布局在字节级完成。这意味着一个bool永远不会少于一个字节依赖于打包。您将不得不做一些更复杂的事情,例如使用两个私有字节字段和多个属性,这些属性引用这些字节中的相应位。

这是一个实现,每个项目都会递增1 << _的右侧以移动到下一个位字段。

[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
}