0

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

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

2 回答 2

2

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

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

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

于 2016-08-31T14:05:47.400 回答
0

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

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

这是一个实现,您增加右侧的每个项目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
}
于 2016-08-31T14:22:26.293 回答