进行P / Invoke时,重要的是使数据布局匹配。
我们可以使用一些属性来控制struct的布局。
例如:
struct MyStruct
{
public bool f;
}
给出大小为4.虽然我们可以告诉编译器使它成为1字节bool来匹配C ++类型 bool
:
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字节大小和对齐方式。
有人能解释一下吗?
更新:我终于找到了,原因是,bool类型在一个结构中,然后该结构将永远不会被blittable!因此,不要指望内部具有bool类型的结构与C中的布局相同。
问候,
翔。
一个 布尔 这是相当特殊的,它可以追溯到Dennis Ritchie决定不给C语言一个bool类型。这引起了大量的混乱,语言和操作系统设计者自己添加了它并做出了不兼容的选择。
它作为BOOL typedef添加到Winapi中。如果您不强制使用其他类型,则这是默认的封送处理。类型定义为 INT 为了使它与C兼容,你发现需要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堆,没有通常的好处 不安全 关键字提醒。但是不可能为速度而战。
你得到一个blittable结构 不 运用 bool
。使用 byte
代替。您仍然可以通过使用属性包装struct成员来获取bool。不要使用自动实现的属性,您必须关心字节的位置。从而:
struct MyStruct
{
private byte _f;
public bool f {
get { return _f != 0; }
set { _f = value ? 1 : 0; }
}
}
本地代码不知道该属性。不要担心getter和setter的运行时开销,抖动优化器会使它们消失,并且它们每个都变为单个CPU指令。
一个 布尔 这是相当特殊的,它可以追溯到Dennis Ritchie决定不给C语言一个bool类型。这引起了大量的混乱,语言和操作系统设计者自己添加了它并做出了不兼容的选择。
它作为BOOL typedef添加到Winapi中。如果您不强制使用其他类型,则这是默认的封送处理。类型定义为 INT 为了使它与C兼容,你发现需要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堆,没有通常的好处 不安全 关键字提醒。但是不可能为速度而战。
你得到一个blittable结构 不 运用 bool
。使用 byte
代替。您仍然可以通过使用属性包装struct成员来获取bool。不要使用自动实现的属性,您必须关心字节的位置。从而:
struct MyStruct
{
private byte _f;
public bool f {
get { return _f != 0; }
set { _f = value ? 1 : 0; }
}
}
本地代码不知道该属性。不要担心getter和setter的运行时开销,抖动优化器会使它们消失,并且它们每个都变为单个CPU指令。
应该管用:
[StructLayout(LayoutKind.Sequential)]
unsafe struct MyStruct
{
public fixed bool fs[5];
}