阿里云备案网站建设方案书案例,营销型网站一站式服务,河北网站建设推广公司,微信小程序哪家开发得好本篇文章介绍C中的内存对齐#xff0c;后续介绍C的union和C的variant的时候#xff0c;需要用到这部分的知识。
占用内存
先回忆下C各个数据类型占用的内存大小#xff1a;
int#xff1a;所占内存大小#xff1a;4byte 32bit#xff1b;char#xff1a;所占内存大小…本篇文章介绍C中的内存对齐后续介绍C的union和C的variant的时候需要用到这部分的知识。
占用内存
先回忆下C各个数据类型占用的内存大小
int所占内存大小4byte 32bitchar所占内存大小1byte 8bit
还有其他的数据类型但是今天就只用这两个。 我们写个结构体
struct s{int x;char y;
};它占用多少byte的内存呢并不是415而是448.
int main()
{printf(%d\n,sizeof(s)); // 输出8return 0;
}分析内存
处理器并不是按字节块来存取内存的。它一般会以2字节,4字节,8字节,16字节甚至32字节为单位来存取内存.我们将上述这些存取单位称为内存存取粒度.写代码的人一般会觉得所有数据结构都会像数组一样有随机存取的特性变量之间是紧挨着的但是对于不同类型的变量来说从内存向寄存器转移数据的过程并不总是顺利的。
以下图片来自https://blog.csdn.net/dxpqxb/article/details/90485917我懒得画图了就直接用现成的了。
现在有4byte的数据存放在内存中他们的地址如下
数据首地址末地址A03B14
假设内存存取粒度是1byte取A和B都只需要取4次即可 当内存存取粒度是2byte时A只需要取两次分别为0和1、2和3但是B从1开始取2次取到了1、2和3第4byte的数据还没取到因此还需要取一次总共取了3次。同时还要把无用的第0byte和第5byte数据丢掉。 当内存存取粒度是4byte时同样的道理A只需要取1次4byteB则需要取2次并丢弃第0第5-7byte的数据。 现在有了内存对齐的int类型数据只能存放在按照对齐规则的内存中比如说0地址开始的内存。那么现在该处理器在取数据时一次性就能将数据读出来了而且不需要做额外的操作提高了效率。
内存对齐
内存对齐的一个原则就是不要让变量跨内存存取粒度存储。
每个特定平台上的编译器都有自己的默认“对齐系数”也叫对齐模数。gcc中默认#pragma pack(4)可以通过预编译命令#pragma pack(n)n 1,2,4,8,16来改变这一系数。
有效对齐值是给定值#pragma pack(n)和结构体中最长数据类型长度中较小的那个。有效对齐值也叫对齐单位。
了解了上面的概念后我们现在可以来看看内存对齐需要遵循的规则 结构体第一个成员的偏移量offset为0以后每个成员相对于结构体首地址的 offset 都是该成员大小与有效对齐值中较小那个的整数倍如有需要编译器会在成员之间加上填充字节。 结构体的总大小为 有效对齐值 的整数倍如有需要编译器会在最末一个成员之后加上填充字节。
我们看下面三个结构体
#include stdio.h
struct x1
{int i;char c1;char c2;
};struct x2
{char c1;int i;char c2;
};struct x3
{char c1;char c2;int i;
};int main()
{printf(%d\n, sizeof(x1)); printf(%d\n, sizeof(x2)); printf(%d\n, sizeof(x3)); return 0;
}不考虑结构体本身对外的偏移量我们以x1为例i的大小是4有效对齐值也是4只要保证偏移量为4的整数倍就行因此i占用0,1,2,3c1和c2的大小都是1有效对齐值为4只要保证偏移量为1的整数倍即可因此占用4和5结构体本身需要对外对齐必须是4的整数倍因此将6和7填充上。其他两个结构体也是一样的分析方式。
现在我们改变有效对齐值为2输出结果如下 依然以x1为例i的大小为4有效对齐值是2只要保证偏移量为2的整数倍就行因此i占用0,1,2,3c1和c2的大小都是1有效对齐值为2只要保证偏移量为1的整数倍即可因此占用4和5结构体本身需要对外对齐必须是2的整数倍无需填充。
其他
C11
对齐的英文是alighmentC11引入了一个函数alignof可以直接获取类型T的内存对齐要求也就是最大的成员大小与有效对齐值中较小那个。比如当有效对齐值为4时上面3个结构体的alignof结果都是4.