结论:结构体的大小计算不仅仅是结构体内所有变量的单纯相加,还应该考虑内存对齐所带来的额外内存
内存对齐
原则上变量可以放在内存中的任意位置,但是为了访问的效率更高,规定变量起始地址只能放在固定的位置上,这个位置为变量对齐数的整数倍。
对齐数
windows:变量对齐数为变量字节数
linux: 变量对齐数为min{变量字节数,cpu字节数}
结构体大小计算
- 结构体内的变量都遵循内存对齐规则
- 结构体整体大小为结构体对齐数的整数倍
结构体对齐数:max{结构体内变量所有对齐数}
例子
struct TEST{
char a;
int b;
double c;
char d;
}
变量内存中分布(windows 32bit):
a: 一定可以放在第一个位置
b: 对齐数为4,只能空出三个字节后,放在第四个字节(从0开始)的位置
c: 对齐数为8,同b
d: 对齐数为1,可以放在任何位置
结构体的对齐数为8,那么结构体大小只能为8的倍数,即是图中全部表格所表示的。
所以结构体的大小为24
主动设置对齐数
可以通过宏pragma自定义变量对齐数
#pragma pack(2) // 将结构体内的所有变量的对齐数设置为2
struct TEST {
char a;
int b;
double c;
char d;
};
#pragma pack() // 取消设置,变量对齐数回到默认值
变量在内存中分布(windows 32bit):
a: 放在首位,无争议
b: 对齐数为2,只能空出一个字节,放在第二个字节(从0开始)的位置
c: 对齐数为2,可以紧挨着b放
d: 对齐数为2,可以紧挨着c放
结构体对齐数为2,所以结构体大小只能为2的倍数,所及结构体为图中所有方格。
结构体大小为16个字节
其他
内存对齐是一种底层要求,不仅仅在结构体中,在类,数组,栈所有数据结构中都会遵守这项制度。只不过由于大部分常见数据结构所存储的都是同一类型的数据,所以不会产生像上面所讲的,因内存对齐而产生空字节浪费。
2023.10.16补充
内存对齐可以从寄存器的角度理解,设备从硬盘中将数据读取到内存中,使用的是寄存器。假设寄存器大小为8位,那么一次读取的位数便是8位,而内存对齐讲的是,任何数据都能够一次便读入到寄存器中。也就是说,数据存储的起始位置必须在同一个寄存器的读取段内,否则就要移动到下一个读取段,从头开始,而中间没有使用到的,便叫作padding,填充字节。