封送包含布尔值的复杂嵌套结构
Marshaling complex nested structures containing booleans
我需要对几个嵌套结构进行复杂的封送处理,其中包含其他结构的可变长度数组,因此我决定使用ICustomMarshaler(请参阅此处的优秀JaredPar教程)。但是我有一个问题,在c++中定义为:
typedef struct AStruct{
int32_t a;
AType* b;
int32_t bLength;
bool aBoolean;
bool bBoolean;
};
在c#端,在ICustomMarshaler
的MarshalManagedToNative
实现中,我使用:
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文件格式,我想映射那些布尔与HDF5库中定义的H5T_NATIVE_UINT8,需要1字节),有没有另一种方式?我的意思是,我能不能在结构体中保证占用1字节?
编辑
同样的问题也适用于int16值:根据由于对齐原因而存在的值的数量,结构体的大小可能与预期的不同。在c#方面,我没有"看到"c++结构体,我只是按照c++结构体的定义在非托管内存上进行编写。这是一个非常简单的过程,但是如果我不得不考虑结构所占用的实际空间(通过猜测或测量它),那么每次修改结构时就会变得更加困难并且容易出错。
这个答案是对汉斯·帕桑说过的话的补充。
让你的结构使用固定的包装尺寸可能是最简单的,这样你就可以很容易地预测成员的布局。但请记住,这可能会影响性能。
这个答案的其余部分是特定于Microsoft Visual c++的,但大多数编译器都提供了自己的变体
要开始,请查看这个SO答案#pragma pack effect和MSDN http://msdn.microsoft.com/en-us/library/2e70t5y1.aspx
您经常使用的是pragma pack(push, ...)
后跟pragma pack(pop, ...)
习语,仅影响在两个pragma之间定义的结构的打包:
#pragma pack(push, 4)
struct someStructure
{
char a;
int b;
...
};
#pragma pack(pop)
这将使someStructure
的每个成员具有可预测的4字节对齐的打包。
编辑:来自MSDN页面上的包装
成员的对齐将在一个n的倍数的边界上或成员大小的倍数,以较小者为准。
所以对于pack(4)
, char
将在1字节边界上对齐,short
在2字节边界上对齐,其余的在4字节边界上对齐。
哪个值最好取决于您的情况。您需要显式地打包您打算访问的所有结构,并且可能是您想要访问的结构的成员的所有结构。
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使用的默认封送处理与BOOL
(winapi中的类型定义)兼容。这是一个32位类型。
所以当你在c#代码中声明结构体时,你必须明确它,你必须告诉编组器你想要1字节类型。这可以通过将结构体成员声明为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项目的平台目标设置为x86。
- 嵌套在类中时无法设置成员数据
- 无法访问嵌套类.类的使用无效
- 我正在使用嵌套的while循环来解析具有多行的文本文件,但由于某种原因,它只通过第一行,我不知道为什么
- 如何在C++中初始化嵌套类中的2个memeber
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 在C++中搜索嵌套多映射值
- 在C++中将矢量转换为嵌套地图
- C++嵌套if语句,基本货币交换
- 具有嵌套 if-else 的循环的时间复杂度
- 2 个嵌套循环的时间复杂度
- 如何在 c++ 下使用嵌套循环和正则表达式降低时间复杂度?
- 为什么使用 2 个嵌套循环 O(n^2) 复杂度来解决二和问题,当只改变循环计数器逻辑时运行得更快?
- 带有 if 语句的嵌套循环的时间复杂度
- 创建复杂的嵌套循环
- 在C++中使用嵌套 for 循环的更复杂的形状
- 嵌套循环的时间复杂度:cn(n+1)/2从何而来
- 如何重写复杂的c++代码行(嵌套的三元操作符)
- 封送包含布尔值的复杂嵌套结构
- Boost::fusion::result_of::as_set(或as_vector)从复杂(嵌套)MPL序列转换
- 一般三个嵌套循环的 O(n^3) 复杂度的数学推导