实验场景:
所有结构体均使用默认的:
StructLayoutAttribute(Value = LayoutKind.Sequential,Pack = 8);
结构体实际大小计算使用:
Marshal.SizeOf(typeof(StructName));
*下面的现象和问题假设在试验场景所用方法都正确下进行,如以上方式有误,请告知
先说说我的理解,结构体中的字段因为需要与Pack大小对齐,所以每次需保证字段的起始地址是Pack大小的整数倍。
//16字节
struct S1
{
sbyte b; //1
long l; //8
}
//16字节
struct S11
{
long l; //8
sbyte b; //1
}
因为long需要8个字节,而前面的sbyte只暂用1个字节,这时候需要额外的浪费7个字节使l字段偏移位置刚好在pack大小的倍数上。
但是下面的2个结构体,成员是一样的(除了顺序),但是大小却是不一样的。
struct S2 //32字节
{
int x; //4
double b; //8
double c; //8
byte a; //1
}
struct S3 //24字节
{
byte a; //1
int x; //4
double b; //8
double c; //8
}
问题1:猜想是a字段与x字段共同占用了第一个pack大小的空间。那么这与字段偏移量是pack大小的整数倍不就相矛盾了?求解释
还有一个现象:
struct S4 //12
{
sbyte s;//1
int i1; //4
int i2; //4
}
问题2:假设字段s与字段i1合并,那么根据前面的结构体S11,应该是16字节。字段i2(相对S11中的字段b)不足pack大小(8字节),补足。但实际为什么事12字节?求解释
5 个解决方案
#1
附上摘自C# 4.0 in nutshell中的一段描述,一直无法理解,很纠结。
For access speed, each field is placed at an offset that is a multiple of the field’s size.
That multiplier, however, is restricted to a maximum of x bytes, where x is the pack
size. In the current implementation, the default pack size is 8 bytes, so a struct comprising
a sbyte followed by an (8-byte) long occupies 16 bytes, and the 7 bytes following
the sbyte are wasted.
For access speed, each field is placed at an offset that is a multiple of the field’s size.
That multiplier, however, is restricted to a maximum of x bytes, where x is the pack
size. In the current implementation, the default pack size is 8 bytes, so a struct comprising
a sbyte followed by an (8-byte) long occupies 16 bytes, and the 7 bytes following
the sbyte are wasted.
#2
和系统有关吧
X86 系统最小分配内存为 4字节,就是Int32
可以用sizeof() 算一下结构体的长度
X86 系统最小分配内存为 4字节,就是Int32
可以用sizeof() 算一下结构体的长度
#4
字节对齐
连续分配,不足8字节的对齐到8字节,如果剩下不足存放下一个变量,则补齐到8字节,下一个8字节开始保存。
连续分配,不足8字节的对齐到8字节,如果剩下不足存放下一个变量,则补齐到8字节,下一个8字节开始保存。
struct S2 //32字节
{
int x; //4 :0~3
double b; //8 :8-4=4,不足以保存double的8字节,所以此处浪费4字节,double b位置:8~16
double c; //8 :17~24
byte a; //1 :25,但根据字节对齐原则,后面7个字节留空
}
struct S3 //24字节
{
byte a; //1 :0
int x; //4 :1~4
double b; //8 :8-5不足以保存double,则浪费3字节,double b位置:8~16
double c; //8 :17~24
}
#5
但是问题中的S4结构体,却是12字节的,按照补足原则应该是16字节吧(Pack为8字节下)。
#1
附上摘自C# 4.0 in nutshell中的一段描述,一直无法理解,很纠结。
For access speed, each field is placed at an offset that is a multiple of the field’s size.
That multiplier, however, is restricted to a maximum of x bytes, where x is the pack
size. In the current implementation, the default pack size is 8 bytes, so a struct comprising
a sbyte followed by an (8-byte) long occupies 16 bytes, and the 7 bytes following
the sbyte are wasted.
For access speed, each field is placed at an offset that is a multiple of the field’s size.
That multiplier, however, is restricted to a maximum of x bytes, where x is the pack
size. In the current implementation, the default pack size is 8 bytes, so a struct comprising
a sbyte followed by an (8-byte) long occupies 16 bytes, and the 7 bytes following
the sbyte are wasted.
#2
和系统有关吧
X86 系统最小分配内存为 4字节,就是Int32
可以用sizeof() 算一下结构体的长度
X86 系统最小分配内存为 4字节,就是Int32
可以用sizeof() 算一下结构体的长度
#3
#4
字节对齐
连续分配,不足8字节的对齐到8字节,如果剩下不足存放下一个变量,则补齐到8字节,下一个8字节开始保存。
连续分配,不足8字节的对齐到8字节,如果剩下不足存放下一个变量,则补齐到8字节,下一个8字节开始保存。
struct S2 //32字节
{
int x; //4 :0~3
double b; //8 :8-4=4,不足以保存double的8字节,所以此处浪费4字节,double b位置:8~16
double c; //8 :17~24
byte a; //1 :25,但根据字节对齐原则,后面7个字节留空
}
struct S3 //24字节
{
byte a; //1 :0
int x; //4 :1~4
double b; //8 :8-5不足以保存double,则浪费3字节,double b位置:8~16
double c; //8 :17~24
}
#5
但是问题中的S4结构体,却是12字节的,按照补足原则应该是16字节吧(Pack为8字节下)。