在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;
}发布于 2016-08-31 22:05:47
尽管C#中的bool类型的大小仅为1字节(sizeof(bool) == 1),但CLR默认为将其封送为非托管BOOL类型。这是调用Marshal.SizeOf时得到的大小。
BOOL是int的Windows SDK标头中的一个类型定义,大小为4个字节。为什么?因为这些头文件是为C语言编写的,当时这种语言没有一流的布尔类型。现在是这样,但出于向后兼容性的原因,这些决定是固定不变的。CLR以这种方式封送调用类型,以便与使用Invoke值的Windows API函数兼容,因为与Windows API的互操作是P/ BOOL的最常见用法。(这与P/Invoke签名的默认调用约定是stdcall而不是cdecl的原因相同。)
若要告诉CLR将bool视为1字节的布尔值,而不是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类型。
发布于 2016-08-31 22:22:26
Glorin Oakenfoot said it much better than I could,所以我将引用他的话
打包/布局是在字节级完成的。这意味着布尔值将永远不会少于一个字节,完全依赖于打包。您必须做一些更复杂的事情,例如使用两个私有字节字段和多个属性,这些属性引用这些字节中的适当位。
这是一个实现,每一项都会从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
}https://stackoverflow.com/questions/39251727
复制相似问题