结构体的大小是多少

任意给定一个结构体,它的大小是多少?
结构体的大小,由两部分组成:成员的大小 + 成员之间的空隙
字节对齐决定了结构体成员之间的空隙大小

字节对齐

结构体字节对齐有2个规则:

  1. 成员的偏移是成员大小的整数倍,这个规则会在成员之间插入空隙
  2. 结构体的总大小是最大成员大小的整数倍,这个规则会在结构体末尾插入空隙。此时,对齐系数就是最大成员的大小。

解释:第二条规则主要用于结构体组成数组的情况,数组的成员之间就不用再插入空隙了

注:

  • 如果结构体成员里有数组,在对齐时当成多个成员来对待
  • 如果制定了对齐系数:#pragma pack(n),其中 n = 1, 2, 4, 8, 16
    • 成员的偏移:取成员大小和 n 中较小的那个数,成员偏移是其整数倍
    • 结构体的总大小:取最大成员大小和 n 中较小的那个数,结构体的大小是其整数倍。此时,对齐系数就是两者中的较小值。

如图所示:
字节对齐.png

如果结构体里面有结构体,那么视内部结构体的对齐系数是其最大元素的对齐系数。
字节对齐-嵌套结构体.png

如果需要跨进程传递结构体,需要保证 pack(1)pack(4) 得到的成员偏移是相同的;如果含有 64 位成员,需要保证 pack(1)pack(8) 成员偏移是一样的。

上述条件可以通过将成员按从大到小的顺序排列达成。这种排列方式,成员之间一定不会出现空隙。(如果成员里面有结构体,需要谨慎考虑)

结构体的起始地址是多少

结构体的起始地址,也存在对齐:

  • 如果没有设置 #pragma pack(n),就取结构体中最大的成员长度作为对齐系数,结构体首地址是其整数倍
  • 如果设置了 #pragma pack(n),就取最大成员长度和 n 中较小的数作为对齐系数

对齐规则,对一般数据也起作用
如图所示:(在 fedora-x86_64-gcc 环境下得到的结果)
字节对齐-数据首地址.png

常见类型大小

  1. # 整形
  2. short # 2
  3. int # 4
  4. long # 不确定的
  5. long long # 8
  6. # 字符
  7. char # 1
  8. # 浮点
  9. float # 4
  10. double # 8
  11. # 指针大小
  12. void* # 32位是4,64位是8

有符号与无符号:

  1. char # 不能确定是有符号还是无符号的
  2. short # signed
  3. int # signed
  4. long # signed
  5. long long # signed