(C语言)结构体内存对齐

阳光穿透心脏的1/2处 2023-10-13 16:10 122阅读 0赞

目录

1.对齐规则

2.示例

例1

例2

例3

3.存在内存对齐的原因

1.平台原因

2.性能原因

4.修改默认对齐数


1.对齐规则

(1)结构体的第一个成员放在偏移量(相较于结构体变量的起始位置)为0的位置

(2)从第二个成员起,之后的每个成员都要对齐到对齐数整数倍的地址处

对齐数:编译器默认的对齐数与该成员大小的较小值

VS中默认为8

Linux中无默认对齐数,对齐数就是成员自身大小

(3)结构体总大小为最大对齐数(所有成员对齐数的最大值)的整数倍

(4)如果出现嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

(5)当出现数组,数组的对齐数为数组元素与默认对齐数的较小值

2.示例

以下均在VS下实现

例1

  1. #include <stdio.h>
  2. struct s1
  3. {
  4. char c1;
  5. int i;
  6. char c2;
  7. };
  8. int main()
  9. {
  10. printf("%d", sizeof(struct s1));//12
  11. return 0;
  12. }

计算结果为12,我们结合内存分布图来计算

c1为char类型,占1个字节,第一个成员放在偏移量为0的位置,(char的对齐数为1)

i为int类型,占4个字节,因此从偏移量为4的位置开始存放

c2为char类型,占1个字节,1为c2的默认对齐数,因此在i的后面接着存放c2,放在偏移量为9的位置处

结构体的最大对齐数为4,结构体的总大小为最大对齐数的整数倍,此时已经使用了9个字节的空间,则结构体的大小为12

6b06f93b0917484498edbff5d19cfdab.png

例2

  1. #include <stdio.h>
  2. struct s1
  3. {
  4. char c1;
  5. int i;
  6. char c2;
  7. };
  8. struct s2
  9. {
  10. char c;
  11. struct s1 s;
  12. int i;
  13. };
  14. int main()
  15. {
  16. printf("%d\n", sizeof(struct s1));//12
  17. printf("%d\n", sizeof(struct s2));//20
  18. return 0;
  19. }

计算结果为20

c为char类型,占1个字节,第一个成员放在偏移量为0的位置,(char的对齐数为1)

由例1计算得出s的大小为12,s为结构体类型,对齐到自己的最大对齐数的整数倍处,s中的3个成员分别为char、int、char类型,最大对齐数为4,因此s对齐到偏移量为4的地址空间处。

i为int类型,对齐数为4,因此对齐到偏移量为16的地址空间处。

此时已经使用20个字节的空间,结构体的最大对齐数为4,因此结构体的大小为20

c378e21a39bb4b73858981b32d592bad.png

例3

  1. #include <stdio.h>
  2. struct s3
  3. {
  4. char c1;
  5. int arr[2];
  6. char c2;
  7. };
  8. int main()
  9. {
  10. printf("%d\n", sizeof(struct s3));//16
  11. return 0;
  12. }

c1为char类型,占1个字节,第一个成员放在偏移量为0的位置,(char的对齐数为1)

arr[2]为数组,当出现数组时,对齐数为元素大小与默认对齐数的最小值,arr[2]的元素为int类型,对齐数为4,因此对齐到偏移量为4的地址空间处

c2为char类型,占1个字节,1为c2的默认对齐数,因此在arr[2]的后面接着存放c2,放在偏移量为12的位置处

a4a896b1c14c4a5e97a348c0c1ca1958.png

3.存在内存对齐的原因

1.平台原因

并不是所有的硬件平台都可以访问任意地址上的任意数据。某些硬件平台只能在某些地址处取得某些特定类型的数据,否则会抛出硬件异常。

2.性能原因

数据结构(尤其是栈)应该尽可能地在自然边界上对齐。

原因:为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问

可以说,结构体的内存对齐是拿空间换时间

当在使用结构体时,为了满足对齐,同时节省空间,可将占用空间小的成员尽量集中在一起

4.修改默认对齐数

结构在对齐方式不合适时,可以自己修改默认对齐数

使用#pragma预处理指令,可以修改默认对齐数(通常设置为2的次方数)

  1. #include <stdio.h>
  2. #pragma pack(4)//设置默认对齐数为4
  3. struct s1
  4. {
  5. // 成员大小 默认对齐数 对齐数
  6. char c;// 1 4 1
  7. double d;//8 4 4
  8. int i;// 4 4 4
  9. };
  10. #pragma pack()//取消设置的默认对齐数,还原为默认对齐数
  11. struct s2
  12. {
  13. // 成员大小 默认对齐数 对齐数
  14. char c;// 1 8 1
  15. double d;//8 8 8
  16. int i;// 4 8 4
  17. };
  18. int main()
  19. {
  20. printf("%d %d", sizeof(struct s1),sizeof(struct s2));
  21. return 0;
  22. }

struct s1

1bad77398e2a45ca9da42620607cc215.png

struct s2

2b55cd64c8634263bc961d15cd631785.png

发表评论

表情:
评论列表 (有 0 条评论,122人围观)

还没有评论,来说两句吧...

相关阅读

    相关 结构体内对齐

    结构体内存对齐规则 > 1. 第一个成员在与结构体变量偏移量为0的地址处。 > 2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 > 对齐数 = 编

    相关 c语言结构体内对齐问题

        c语言中结构体使用是非常广泛的,但是结构体有一个问题,就是如果开头的字段属性是字符类型(char),紧跟着的是其他类型,比如整型、长整型、双精度、浮点型,这时候结构体的

    相关 676-为什么要进行结构体内对齐

    为什么要进行结构体内存对齐? 1、平台移植型好 不是所有的硬件平台都能访问任意地址上的数据;某些硬件平台只能只在某些地址访问某些特定类型的数据,否则抛出硬件异常,及遇

    相关 关于结构体内对齐总结

    内存对齐计算可谓是笔试题的必考题,但是如何按照计算原则算出正确答案一开始也不是很容易的事,所以专门通过例子来复习下关于结构体内存对齐的计算问题。(编译环境为vs2015)