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



在c#中,我创建了包含16个bool类型变量的多个不同结构体。我将有几个不同的结构体,然后将它们与其他数据类型组合成更复杂的结构体。我需要将它们视为2字节的长度。在下面的代码中,当我执行封送操作时,创建了一个类型为CtrlWord1的变量,它的长度为64。SizeOf,不管它是用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;
}

尽管c#中的bool类型只有1字节大小(sizeof(bool) == 1), CLR默认将其编组为非托管BOOL类型。这是您调用Marshal.SizeOf时得到的大小。

BOOL是Windows SDK头文件中int的类型定义,大小为4字节。为什么?因为这些头文件是为C语言编写的,当时这种语言还没有一等布尔类型。现在可以了,但是由于向后兼容性的原因,这些决定是固定不变的。CLR以这种方式封送bool类型,以便与使用BOOL值的Windows API函数兼容,因为与Windows API互操作是P/Invoke最常见的用法。(与P/Invoke签名的默认调用约定是stdcall而不是cdecl的原因相同。)

使用MarshalAs属性告诉CLR将bool s视为1字节的bool,而不是4字节的BOOL s。不幸的是,你必须使用它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类型。

gloria Oakenfoot说得比我好得多,所以我只引用他的话

包装/布局是在字节级完成的。这意味着纯粹依靠打包,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
}

相关内容

  • 没有找到相关文章

最新更新