结构体在C语言中也是很常见并且也是运用非常广泛的,这篇博客主要给大家介绍一下在结构体中的内存对齐问题,这个内存对齐问题,是现在很常见的以"以空间换时间"的案例,这个主要因为,现在硬盘空间越来越大,现在空间很大并且已经变得廉价,所以会有以“以空间换取时间”,这样会使得时间效率更大化。下面进入正题。
什么是内存对齐呢?说起来可能比较抽象,老样子,给代码以运行结构了解一下。
struct S1
{
char c1;
int i;
char c2;
};
struct S2
{
char c1;
char c2;
int i;
};
int main()
{
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
}
运行结构如下:
可以看到在两个结构体中,只是调换了数据类型的位置,结果打印的结构就不一样了,使得他们产生巨大化差异的就是内存对齐。
在进行内存对齐的时候我们首先要知道对齐规则:
1.第一个成员在与结构体变量偏移量为0的地址处。
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数=编译器默认的一个对齐数与该成员大小的较小值。(在vs编译环境下默认对齐数为8,在Linux编译环境下为4。
首先了解一下这前两个规则,规则一就是说在结构体中第一个成员直接存放进内存即可。而规则二在说其他成员应该按照对齐数的整数倍存放,这个对齐数就是默认对齐数与该成员变量大小的较小值。在第一个程序中,第一个是char c1,占一个字节。而后是int i,占四个字节,因为四个字节比默认的八个字节小,所以对齐数就是4,所以int i就应该存放在4的整数倍处,然后它占4个字节,最后是Char c2,这个大小是1,与默认对齐数相比较这个对齐数就是1,所以,存放一个字节。可能我说的比较抽象,给大家画个图
这就是上述我所描写的应该存放的数据大小,为9个字节,那为什么结果是12呢?这就和前面我所说的以空间换时间有关,下面请了解一下第三条规则:
3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
因为在这两个成员变量中,都有一个对齐数,这时候字节的总大小就是最大对齐数的整数倍,所以4的整数倍最小的应该就是12。所以打印为12。
在第二个程序运行结果为8,因为调换了位置,所以在c1之后就可以存放c2,1的整数倍是任何数字,然后在第四个字节处存放i,i占四个字节,所以打印结果为8.下面给图,画的不太好
最后一条规则是关于在结构体中嵌套一个结构体的内存对齐问题,规则如下:
如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
这个我们给代码说明一下。
struct S3{
double d;
char c;
int i;
};
struct S4
{ char c1;
struct S3 s3;
double d;
};
int main()
{
printf("%d\n", sizeof(struct S3));
printf("%d\n", sizeof(struct S4));
}
运行结果如下:
第一个运行结果为16,这个可以用上面规则1 2 3说明清楚,这里不做赘述,主要看第二个运行结果
首先嵌套的结构体最大对齐数为8,先存放C1,占一个字节,然后对齐到8的整数倍8的字节处,占16个字节,这时候在空间中已经开辟了24个,最后24也是最后double d的整数倍,直接存储,成为32个字节大小,这时候已经存放完毕后判断整个结构体最大的对齐数,得是这个最大对齐数的整数倍才可以结束,这个程序中最大对齐数是8,所以最后结果为32,给个图说明一下:
所以以后在结构体成员的设置中,尽可能的让小的存放在一起。这样的效率会更高。以上就是我个人关于结构体成员变量中关于内存对齐问题的一点小理解,如果有大佬觉得我写的不太清楚,可以在底下留言。希望各位大佬不吝赐教。