结构中C#fixed bool数组的大小和对齐方式是什么?

时间:2016-01-07 05:20:06

标签: c# pinvoke

进行P / Invoke时,重要的是使数据布局匹配。

我们可以通过使用某个属性来控制struct的布局。

例如:

struct MyStruct 
{
    public bool f;
}

给出4的大小。虽然我们可以告诉编译器使它成为1字节bool以匹配bool的C ++类型:

struct MyStruct
{
    [MarshalAs(UnmanagedType.I1)]
    public bool f;
}

的大小为1。

这些都有道理。但是当我测试固定的bool数组时,我很困惑。

unsafe struct MyStruct
{
    public fixed bool fs[1];
}

给出4个字节的大小。和

unsafe struct MyStruct
{
    public fixed bool fs[4];
}

仍然给出4个字节的大小。但

unsafe struct MyStruct
{
    public fixed bool fs[5];
}

的大小为8。

看起来在固定的bool数组中,bool元素的大小仍然是1个字节,但是对齐是4个字节。这不匹配C ++ bool数组,它是1字节大小和对齐。

有人能解释一下吗?

更新:我终于找到了,原因是,在一个struct中bool类型,然后该结构永远不会被blittable!因此,不要期望内部具有bool类型的结构与C中的布局相同。

此致 项。

2 个答案:

答案 0 :(得分:13)

bool 比较特别,它可以追溯到Dennis Ritchie决定不给C语言一个bool类型。这引起了大量的混乱,语言和操作系统设计者自己添加了它并做出了不相容的选择。

它作为BOOL typedef添加到Winapi中。如果您不强制使用其他类型,则这是默认的封送处理。键入为 int 以保持与C兼容,如您所知,需要4个字节。正如你所发现的那样,对齐到4,就像任何 int 那样。

它被添加到C ++中。没有大小规范,大多数C ++编译器实现选择单个字节进行存储。最值得注意的是Microsoft C ++编译器,你最可能实现的实现。

它作为VARIANT_BOOL添加到COM Automation。最初的目标是作为Visual Basic的新扩展模型来摆脱VBX限制,它变得非常流行,而且几乎所有Windows上的语言运行时都支持它。那时VB很大程度上受到16位操作系统敏感性的影响,VARIANT_BOOL需要2个字节。

所有三个本机运行时环境都可能是C#程序中互操作的目标。很明显,CLR设计者有一个非常困难的选择,必须选择1,2和4个字节。没有办法获胜,而CLR确实有机会猜测COM互操作,它无法知道你是否尝试与基于C的api或C ++程序互操作。所以他们做出了唯一合乎逻辑的选择:没有一个。

包含bool的结构或类类型永远不会是 blittable 。即使应用[MarshalAs(UnmanagedType.U1)],也不会使它与CLR类型兼容。不太确定这是一个很好的决定,但它是他们制作的那个,所以我们必须处理它。

获得一个blittable结构是非常需要的,它避免了复制。它允许本机代码直接访问托管堆和堆栈。非常危险且许多破坏的pinvoke声明已损坏GC堆,而没有 unsafe 关键字警报的通常好处。但是不可能为速度而战。

你使用bool通过而不是得到一个blittable结构。请改用byte。您仍然可以通过使用属性包装struct成员来获取bool。不要使用自动实现的属性,您必须关心字节的位置。因此:

struct MyStruct 
{
    private byte _f;
    public bool f {
        get { return _f != 0; }
        set { _f = value ? 1 : 0; }
    }
}

原生代码无视该属性。不要担心getter和setter的运行时开销,抖动优化器会使它们消失,并且每个都会转换为单个CPU指令。

答案 1 :(得分:-1)

应该工作:

[StructLayout(LayoutKind.Sequential)]
unsafe struct MyStruct
{
   public fixed bool fs[5];
}