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

结构体内存对齐规则:

1.第一个成员在与结构体变量偏移量为0 的地址处。

2.其他成员变量要对齐到某个数字(对其数)的整数倍的地址处。

  对齐数 = 编译器默认的一个对齐数 与 该成员大小的 较小值。

  vs 中默认的值为 8

3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

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

实际应用

#include<stdio.h>

struct s1
{
    char c1;
    int a;
    char c2;
};

struct s2
{
    char c1;
    char c2;
    int a;
};

int main()
{
    struct s1 s1 = {0};
    printf("%d\n",sizeof(s1));
    struct s2 s2 = {0};
    printf("%d\n",sizeof(s2));
    return 0;
}

这段代码输出的结果为:

12

8

下面我们来逐一分析:

s1 

c1为char型,占一个字节,第一个成员即 c1 在与结构体变量偏移量为0 的地址处。

a为int型,占四个字节,对齐数是4,对齐到4的整数倍的地址处,即偏移量为4开始的地址空间。

c2为char型,占一个字节,对齐数是1,对齐到1的整数倍的地址处,即偏移量为8开始的地址空间。

结构体总大小为最大对齐数的整数倍,所以为对齐数4的整数倍,现在已经用了9个字节的空间,那么总大小就是12个字节空间。

所以输出结果是12。

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

s2

c1为char型,占一个字节,第一个成员即 c1 在与结构体变量偏移量为0 的地址处。

c2为char型,占一个字节,对齐数是1,对齐到1的整数倍的地址处,即偏移量为1开始的地址空间。

a为int型,占四个字节,对齐数是4,对齐到4的整数倍的地址处,即偏移量为4开始的地址空间。

结构体总大小为最大对齐数的整数倍,所以为对齐数4的整数倍,现在已经用了8个字节的空间,那么总大小就是8个字节空间。

所以输出结果是8。

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

 

结构体的嵌套使用情况

#include<stdio.h>

struct s3
{
    double d;
    char c;
    int i;
};

struct s4
{
    char a;
    struct s3 s3;
    double b;
};

int main()
{
    struct s4 s4;
    printf("%d\n",sizeof(s4));
    return 0;
}

结果为:32

由以上方法容易得出struct S3占16个字节,最大对齐数为:8。

a为char型,占一个字节,第一个成员即 c1 在与结构体变量偏移量为0 的地址处。

第二个成员是结构体嵌套使用,结构体S3变量s3,刚才已经得出占16个字节,最大对齐数是8,所以对齐到偏移量为8的地址空间。

b为double型,占八个字节,对齐数是8,对齐到8的整数倍的地址处,即偏移量为24开始的地址空间。

结构体总大小为最大对齐数的整数倍,所以为对齐数8的整数倍,现在已经用了32个字节的空间,那么总大小就是32个字节空间。

所以输出结果是32。

 

s3                                                                                         

 

 

 

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

s4

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

 

为什么存在内存对齐:

1.平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否者抛出硬件异常。

2.性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要做两次内存访问;而对齐的内存访问仅需要一次访问。

总体来说:

结构体的内存对齐是拿空间来换取时间的做法。

那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:

让占用空间小的成员尽量集中在一起。

struct s1
{
    char c1;
    int a;
    char c2;
};

struct s2
{
    char c1;
    char c2;
    int a;
};

s1 和 s2 类型的成员一模一样,但是s1和s2所占的空间的大小有了一些区别。

设置默认对齐数: 

#pragma pack(8)//设置默认对齐数为8
struct s1
{
    char c1;
    int i;
    char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认

 

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

上一篇:HashMap底层红黑树实现(自己实现一个简单的红黑树)


下一篇:java2-流程控制