当前位置:网站首页>结构体的内存对齐问题

结构体的内存对齐问题

2022-08-10 03:29:00 iccoke

结构体的内存对齐

结构体的大小不是结构体元素单纯相加就行的,因为我们主流的计算机使用的都是32bit字长的CPU,对这类型的CPU取4个字节的数要比取一个字节要高效,也更方便。所以在结构体中每个成员的首地址都是4的整数倍的话,取数据元素时就会相对更高效,这就是内存对齐的由来。每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。

结构体内存对齐规则:


第一个成员在结构体变量偏移量为0 的地址处。
其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数 = 编译器默认的一个对齐数与该成员大小中的较小值。vs中默认值是8 Linux默认值为4.
结构体总大小为最大对齐数的整数倍。(每个成员变量都有自己的对齐数)
如果嵌套结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(包含嵌套结构体的对齐数)的整数倍。


结构体内存对齐规则的应用

例如这里我们定义一个结构体,应用结构体内存对齐原则我们进行结构体大小的判断

struct Student {
    short b;
    char c;
    int a;
    long int d;
    double g;

};

直接简单加法的话,这个结构体的大小应该是19;那么我们打印一下他的大小

实际上应该是24,那么我们是怎么得到这个24的呢

首先b先存入内存中,那么c存入时对于的地址就是2,时c的整数倍,那么c就可以存到3这个位置,然后再存入a,对应的首地址是3,不是int 的整数倍,我们就要在c后面浪费一个字节使其满足结构体的内存对齐规则,然后再存入d,地址是8,是long int的整数倍,最后再存入g,地址是12,不是double的整数倍,然后应该在d后面浪费4个四个字节以求满足结构体的内存对齐问题,然后最后在判断整个结构体的大小是不是结构体内最大基本类型和默认内存对齐数中比较小的数的整数倍,double 类型占8个字节,vs中默认结构体对齐数是8,所以大小应该是8的整数倍,我们判断为24是正确的,符合内存对齐的规则

那么对于嵌套的结构体我们又该如何计算呢,这里我们举一个例子

struct S1
{
    double d;
    char c;
    int i;
};
struct S2
{
    char c1;
    struct S1 s3;
    double d;
};
printf("%d\n", sizeof(struct S2));

那么这里的结果应该如何来看呢,应该是32,这里我们放到内存上来看就会比较清晰

 

 当计算完得到结果之后一定要严格的按照结构体的内存对齐规则进行验证

//* #pragma pack(字节)  对齐方式开始 预处理指令
//* #pragma pack()   对齐方式结束 预处理指令

这个指令可以改变系统提供的默认对齐数

例如#pragam pack(1)

#pragma pack()

这个分别使用在结构体的前后,这样既可以让结构体的对齐书改为1使用

结构体实际上是牺牲空间换取时间上的便利

原网站

版权声明
本文为[iccoke]所创,转载请带上原文链接,感谢
https://blog.csdn.net/iccoke/article/details/126224947