使用位域的结构大小不正确
Incorrect struct size using bitfields
我最近不得不处理结构中的位域,遇到了一个我无法解释的行为。
下面的struct应该是9字节,根据个人sizeof。但是对主结构执行 sizeof 会产生 10 个字节。
以下程序产生“10;1 1 2 1 2 1 1 =9”
int main(){
struct{
uint8_t doubleoscillator;
struct{
char monophonic : 1;
char hold : 1;
char padding : 6;
} test;
int16_t osc1_multisound; //int
int8_t osc1_octave; // -2..1
int16_t osc2_multisound; //int
int8_t osc2_octave; // -2..1
int8_t intervall;
}osc;
std::cout << sizeof(osc) << "; ";
int a[7];
a[0] = sizeof(osc.doubleoscillator);
a[1] = sizeof(osc.test);
a[2] = sizeof(osc.osc1_multisound);
a[3] = sizeof(osc.osc1_octave);
a[4] = sizeof(osc.osc2_multisound);
a[5] = sizeof(osc.osc2_octave);
a[6] = sizeof(osc.intervall);
int total = 0;
for(int i=0;i<7;i++){
std::cout << a[i] << " ";
total += a[i];
}
std::cout << " = " << total << std::endl;
return 0;
}
为什么结构内部变量的单个 sizeof() 总和与 osc
结构的 sizeof() 产生不同的结果?
主要是出于性能原因,在结构的每个成员之前添加填充以在结构的内存布局中对齐所述成员。因此 ocs2_multisound
之前可能有一个填充字节,以确保它出现在结构中的字节数是 2 的倍数(因为 int16_t
的对齐方式为 2)。
此外,在完成所有这些之后,结构的总大小被填充到其最严格对齐要求(即任何保留字段的最高对齐)的倍数。这是这样的,例如所述类型的数组元素将全部正确对齐。
可以在编译时通过 alignof(T)
检查类型的对齐方式,其中 T
是类型。
在这种情况下,增加大小是不可避免的,但减少填充字节的常见建议是按降序对齐的顺序对结构成员进行排序。这是因为下一项可以保证在不需要填充的情况下正确对齐,因为前一个字段要么是相同的对齐方式,要么是更严格的对齐方式。所以如果添加任何填充,它只会填充结构的总大小,而不是(浪费)字段之间的填充。
现在对齐主要是为了效率。在支持它的硬件上读取未对齐的内存块通常要慢两倍左右,因为它实际上是在读取它周围的两个内存块并提取它需要的内容。但是,如果您尝试 read/write 未对齐内存,也有一些硬件根本无法工作。此类硬件通常会在此事件中触发硬件异常。
我最近不得不处理结构中的位域,遇到了一个我无法解释的行为。
下面的struct应该是9字节,根据个人sizeof。但是对主结构执行 sizeof 会产生 10 个字节。
以下程序产生“10;1 1 2 1 2 1 1 =9”
int main(){
struct{
uint8_t doubleoscillator;
struct{
char monophonic : 1;
char hold : 1;
char padding : 6;
} test;
int16_t osc1_multisound; //int
int8_t osc1_octave; // -2..1
int16_t osc2_multisound; //int
int8_t osc2_octave; // -2..1
int8_t intervall;
}osc;
std::cout << sizeof(osc) << "; ";
int a[7];
a[0] = sizeof(osc.doubleoscillator);
a[1] = sizeof(osc.test);
a[2] = sizeof(osc.osc1_multisound);
a[3] = sizeof(osc.osc1_octave);
a[4] = sizeof(osc.osc2_multisound);
a[5] = sizeof(osc.osc2_octave);
a[6] = sizeof(osc.intervall);
int total = 0;
for(int i=0;i<7;i++){
std::cout << a[i] << " ";
total += a[i];
}
std::cout << " = " << total << std::endl;
return 0;
}
为什么结构内部变量的单个 sizeof() 总和与 osc
结构的 sizeof() 产生不同的结果?
主要是出于性能原因,在结构的每个成员之前添加填充以在结构的内存布局中对齐所述成员。因此 ocs2_multisound
之前可能有一个填充字节,以确保它出现在结构中的字节数是 2 的倍数(因为 int16_t
的对齐方式为 2)。
此外,在完成所有这些之后,结构的总大小被填充到其最严格对齐要求(即任何保留字段的最高对齐)的倍数。这是这样的,例如所述类型的数组元素将全部正确对齐。
可以在编译时通过 alignof(T)
检查类型的对齐方式,其中 T
是类型。
在这种情况下,增加大小是不可避免的,但减少填充字节的常见建议是按降序对齐的顺序对结构成员进行排序。这是因为下一项可以保证在不需要填充的情况下正确对齐,因为前一个字段要么是相同的对齐方式,要么是更严格的对齐方式。所以如果添加任何填充,它只会填充结构的总大小,而不是(浪费)字段之间的填充。
现在对齐主要是为了效率。在支持它的硬件上读取未对齐的内存块通常要慢两倍左右,因为它实际上是在读取它周围的两个内存块并提取它需要的内容。但是,如果您尝试 read/write 未对齐内存,也有一些硬件根本无法工作。此类硬件通常会在此事件中触发硬件异常。