我需要对几个嵌套结构进行复杂的编组,包含可变长度数组到其他结构,因此我决定使用ICustomMarshaler(参见一个好的JaredPar&#39教程here)。但是我在C ++中定义的结构有一个问题:
typedef struct AStruct{
int32_t a;
AType* b;
int32_t bLength;
bool aBoolean;
bool bBoolean;
};
在C#方面,我正在使用的MarshalManagedToNative
ICustomMarshaler
实现:
Marshal.WriteByte(intPtr, offset, Convert.ToByte(aBoolean));
offset += 1;
Marshal.WriteByte(intPtr, offset, Convert.ToByte(bBoolean));
但是由于我发现C ++结构中的每个bool都占用了2个字节,所以它无效。确实在x86 sizeof(AStruct) = 16
中,而不是14.好吧,bool不能保证占用1个字节,因此我尝试使用unsigned char
和uint8_t
但仍然是16。
现在,我知道我可以使用int32而不是布尔值,但是因为我关心所占用的空间,并且有几个结构包含流向磁盘的布尔值(我使用HDF5文件格式,我想用这些布尔值映射H5T_NATIVE_UINT8在HDF5库中定义,占用1个字节),还有另外一种方法吗?我的意思是我可以在结构内部保留一个字节吗?
修改
同样的问题也适用于int16值:取决于由于对齐原因而存在多少个值,结尾处结构的大小可能与预期的不同。在C#方面,我没有"看到"在C ++结构中,我只是通过遵循C ++中我的结构的定义来编写非托管内存。这是一个非常简单的过程,但如果我反而考虑结构所采用的真实空间(通过猜测或测量它),每次修改结构时都会变得更加困难和容易出错。
答案 0 :(得分:2)
sizeof(AStruct)= 16,而不是14
这是对的。结构在末尾有两个额外的字节,未使用。如果将结构放在数组中,它们确保结构中的字段仍然正确对齐。在32位模式下,int32_t
和AType*
成员需要4个字节,并且应该与4的倍数对齐,以允许处理器快速访问它们。只有当结构大小是4的倍数时才能实现这一点。因此,14被四舍五入为16。
请注意,不意味着bool
字段占用2个字节。 C ++编译器只使用1个字节。额外的2个字节是纯填充。
如果在C#程序中使用Marshal.SizeOf(typeof(AStruct)),那么你会发现你声明的结构需要20个字节。这不好,你正试图解决的问题。 bool 成员是问题,这个问题一路走来,回到早期版本的C语言。哪个没有bool类型。 CLR使用的默认封送处理与winapi中的typedef BOOL
兼容。这是一个32位类型。
因此,当您在C#代码中声明结构时,必须明确它,您必须告诉编组器您需要1字节类型。通过将struct成员声明为 byte 来执行此操作。或者通过覆盖默认编组:
[StructLayout(LayoutKind.Sequential)]
private struct AStruct{
public int a;
public IntPtr b;
public int bLength;
[MarshalAs(UnmanagedType.U1)]
public bool aBoolean;
[MarshalAs(UnmanagedType.U1)]
public bool bBoolean;
}
现在您将看到Marshal.SizeOf()现在返回16.请注意,您必须以32位模式强制执行程序,确保EXE项目的Platform Target设置为x86。
答案 1 :(得分:2)
这个答案是Hans Passant所说的。
让您的结构使用固定的包装尺寸可能最容易,因此您可以轻松预测成员布局。请记住,这可能会影响性能。
本答案的其余部分特定于Microsoft Visual C ++,但大多数编译器都提供了自己的变体。
为了帮助您入门,请查看此SO回答#pragma pack effect和MSDN http://msdn.microsoft.com/en-us/library/2e70t5y1.aspx
您经常使用的是pragma pack(push, ...)
后跟pragma pack(pop, ...)
成语,仅影响两个编译指示之间定义的结构的打包:
#pragma pack(push, 4)
struct someStructure
{
char a;
int b;
...
};
#pragma pack(pop)
这将使someStructure
具有每个成员的4字节对齐的可预测包装。
编辑:从包装上的MSDN页面
成员的对齐将位于n的倍数的边界上 或者成员大小的倍数,以较小者为准。
因此对于pack(4)
,char
将在1字节边界上对齐,在{2}字节上对齐short
,其余在4字节边界上。
哪个值最好取决于您的情况。您需要明确打包您打算访问的所有结构,以及可能是您要访问的结构成员的所有结构。