我最近不得不处理结构中的位字段,并且遇到了一个我无法解释的行为。
根据个体sizeof,以下结构应为9个字节。但是执行main struct的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;
}
为什么struct的内部变量的个别sizeof()与osc
结构的sizeof()产生不同的结果?
主要出于性能原因,在结构的每个成员之前添加填充以在结构的内存布局中对齐所述成员。因此ocs2_multisound
可能在它之前有一个填充字节,以确保它出现在结构的多个字节中,是2的倍数(因为int16_t
的对齐为2)。
此外,在完成所有操作之后,将结构的总大小填充到其最严格的对齐要求的倍数(即任何保持字段的最高对齐)。这是这样的,例如所述类型的数组的元素将全部正确对齐。
可以在编译时通过alignof(T)
检查类型的对齐,其中T
是类型。
在这种情况下,增加的大小是不可避免的,但减少填充字节的常见建议是按顺序降序排序struct成员。这是因为保证下一项正确对齐而不需要填充,因为前一个字段是相同的对齐或更严格的对齐。因此,如果添加任何填充,则仅填充结构的总大小,而不是填充字段之间的(浪费)填充。
对齐的原因主要是为了提高效率。在支持它的硬件上读取未对齐的内存块通常是慢两倍,因为它实际上正在读取它周围的两个内存块并提取它所需的内容。但是,如果您尝试读取/写入未对齐的内存,那么硬件也无法正常工作。此类硬件通常会在此事件中触发硬件异常。