结构体的大小是多少
任意给定一个结构体,它的大小是多少?
结构体的大小,由两部分组成:成员的大小 + 成员之间的空隙
字节对齐决定了结构体成员之间的空隙大小
字节对齐
结构体字节对齐有2个规则:
- 成员的偏移是成员大小的整数倍,这个规则会在成员之间插入空隙
- 结构体的总大小是最大成员大小的整数倍,这个规则会在结构体末尾插入空隙。此时,对齐系数就是最大成员的大小。
解释:第二条规则主要用于结构体组成数组的情况,数组的成员之间就不用再插入空隙了
注:
- 如果结构体成员里有数组,在对齐时当成多个成员来对待
- 如果制定了对齐系数:
#pragma pack(n)
,其中n = 1, 2, 4, 8, 16
- 成员的偏移:取成员大小和
n
中较小的那个数,成员偏移是其整数倍 - 结构体的总大小:取最大成员大小和
n
中较小的那个数,结构体的大小是其整数倍。此时,对齐系数就是两者中的较小值。
- 成员的偏移:取成员大小和
如图所示:
如果结构体里面有结构体,那么视内部结构体的对齐系数是其最大元素的对齐系数。
如果需要跨进程传递结构体,需要保证 pack(1)
和 pack(4)
得到的成员偏移是相同的;如果含有 64 位成员,需要保证 pack(1)
和 pack(8)
成员偏移是一样的。
上述条件可以通过将成员按从大到小的顺序排列达成。这种排列方式,成员之间一定不会出现空隙。(如果成员里面有结构体,需要谨慎考虑)
结构体的起始地址是多少
结构体的起始地址,也存在对齐:
- 如果没有设置
#pragma pack(n)
,就取结构体中最大的成员长度作为对齐系数,结构体首地址是其整数倍 - 如果设置了
#pragma pack(n)
,就取最大成员长度和n
中较小的数作为对齐系数
对齐规则,对一般数据也起作用
如图所示:(在 fedora-x86_64-gcc
环境下得到的结果)
常见类型大小
# 整形
short # 2
int # 4
long # 不确定的
long long # 8
# 字符
char # 1
# 浮点
float # 4
double # 8
# 指针大小
void* # 32位是4,64位是8
有符号与无符号:
char # 不能确定是有符号还是无符号的
short # signed
int # signed
long # signed
long long # signed