C/C++内存对齐

前言

C语言中,结构体内存对齐问题算是比较常见的问题,虽然理解起来不难,但很多时候一不小心就会算错。比如给你一个 struct,让你 sizeof 计算一下需要占用多少字节,往往得到的结果比等于 struct 里面数据成员所占用的字节之和。

例:

#include <stdio.h>

struct {
    int a;  // 4
    char b; // 1
} test;


int main(void) { 
    printf("%d
", sizeof(test));
    return 0;
}

输出:

8

分析:

C语言中,int 占4个字节,char 占1个字节,理想情况下,这个结构体应该占用5个字节才对,为什么 sizeof 的结果却是8,这就不得不提到内存对齐了。

内存对齐

原则

1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在 offset = 0 的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

3、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。

例1:

#include <stdio.h>

struct {
    int a;  // 4
    char b; // 1
} test;


int main(void) { 
    printf("%d
", sizeof(test));
    return 0;
}

输出:8
分析:根据原则1、原则2,结构体中最大的成员是a,占用4字节,a存放在[0,3]中,b存放在[4],但由于原则2,需要对b进行补齐,b后面[5,7]需要填充,所以最终的结果是8

例2:

#include <stdio.h>

struct {
    int a;   // 4
    char b;  // 1
    short c; // 2
} test;


int main(void) { 
    printf("%d
", sizeof(test));
    return 0;
}

输出:8

分析:根据原则1和原则2,a存放在[0,3],b存放在[4],c存放在[6,7],b后面一个字节需要填充对齐

例3:

#include <stdio.h>

struct {
    char a;  // 1
    int b;   // 4
    short c; // 2
} test;


int main(void) { 
    printf("%d
", sizeof(test));
    return 0;
}

输出:12

分析:根据原则1和原则2,a存放在[0],b存放在[4,7],c存放在[8,9],a后面需要填充3个字节,c后面需要填充2个字节

疑问:

为什么例2和例3结构体内部成员都一致,只不过调整下顺序,内存占用却不一样?其实C语言在分配内存的时候,是根据结构体的成员属性定义从上往下进行分配的,有经验的程序员会在写结构体的时候对内存这块进行优化,从而提高代码的整体效率。

在设计结构体的时候,一般会遵照一个习惯,就是把占用空间小的类型排在前面,占用空间大的类型排在后面,这样可以相对节约一些对齐空间。

例4:

#include <stdio.h>

struct {
    char b[2];  // 2
    int c;      // 4
    double d;   //8
    short e;    // 2
    struct {
        int f;    // 4
        double g; // 8
        short h;  // 2
    }a;
    int i;      //4
} test;


int main(void) { 
    printf("%d
", sizeof(test));
    return 0;
}

输出:56

分析:结构体中含有结构体,则整体按最大数据成员 double 所占用8个字节的整数倍进行分配

总结

在计算机中,要么时间换空间,要么空间换时间,很明显,内存对齐就是空间换时间,按照一定的对齐规则,内存对齐的作用不仅是便于cpu快速访问,同时合理的利用内存对齐可以有效地节省存储空间。简而言之,内存对齐是为了高效的内存IO。

原文地址:https://www.cnblogs.com/lyc94620/p/14800754.html