C语言程序设计 | 结构体内存对齐

c语言在计算自定义的结构体的内存时常常要考虑到结构体内存对齐,那么什么是结构体内存对齐呢?

结构体内存对齐规则

1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
        对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值
        VS中默认的值为8
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
例如下列代码
struct  s1
{
    char  c1;   //默认对齐数:8  vs  变量C1所占字节数:1  ——>对齐数:1
    int   i;    //默认对齐数:8  vs  变量i所占字节数:4  ——>对齐数:4
    char  c2;   //默认对齐数:8  vs  变量c2所占字节数:1 ——>对齐数:1
}

//结构体所占大小为 12个字节
//结构体的最大对齐数:4

在内存中表示为:

C语言程序设计 | 结构体内存对齐_第1张图片

因为在结构体s1中,第二个变量i的对齐数是4,所以变量i的存储的地址必须为四的倍数,导致第一个变量c1占完第一个字节后,后面三个字节没有被利用,而是到第四个字节处存储第二个变量i。

当我们调换变量顺序后,结构体占用内存的大小可能会发生变化,例如:

struct  s2
{
    char  c1;     //默认对齐数:8  vs  变量C1所占字节数:1  ——>对齐数:1
    char  c2;     //默认对齐数:8  vs  变量C2所占字节数:1  ——>对齐数:1
    int  i;       //默认对齐数:8  vs  变量i所占字节数:4  ——>对齐数:4
}

//结构体所占大小为 8个字节
//结构体最大对齐数:4

在内存中表示为:

C语言程序设计 | 结构体内存对齐_第2张图片

因为第一个变量c1和第二个变量c2的对齐数都是1,所以第一个字节的位置和第二个字节的位置都是1的倍数,因此第一个字节和第二个字节用来存储第一个变量c1和第二个变量c2,而第三个变量i的对齐数是4,所以在第四个字节(4的倍数)的位置存储i。

同理,对于以下代码:

struct  s3
{
    double  d;    //默认对齐数:8  vs  变量d所占字节数:8  ——>对齐数:8
    char  c;      //默认对齐数:8  vs  变量c所占字节数:1  ——>对齐数:1
    int  i;       //默认对齐数:8  vs  变量i所占字节数:4  ——>对齐数:4
}

//结构体大小:16
//结构体最大对齐数:8

C语言程序设计 | 结构体内存对齐_第3张图片

而对于嵌套的结构体来说:

struct  s4
{
    char  c1;         //默认对齐数:8  vs  变量c1所占字节数:1  ——>对齐数:1
    struct  S3 s3;    //默认对齐数:8  vs  变量s3所占字节数:8  ——>对齐数:8
    double  d;        //默认对齐数:8  vs  变量d所占字节数:8  ——>对齐数:8
}     

//结构体大小:32
//结构体最大对齐数:8

 C语言程序设计 | 结构体内存对齐_第4张图片

因为变量s3的对齐数是8,所以在第一个字节被变量c1使用后,跳过七个字节,在第八个字节的位置(8的倍数)存储s3。

以上就是关于c语言中结构体内存对齐的知识了,那么为什么结构体要内存对齐了,有以下三个方面的原因:

  1. 不是所有的硬件平台都能访问任意地址上的数据;

  2. 某些硬件平台只能只在某些地址访问某些特定类型的数据,否则抛出硬件异常,及遇到未对齐的边界直接就不进行读取数据了。

  3. 为了代码的可移植性,和提升CPU访问内存的效率,所以结构体一定要内存对齐。

 结构体的内存对齐本质上来说是 以空间换时间 来提高结构体的高效性。

你可能感兴趣的:(C语言知识点整理,c语言)