《C语言笔记:结构体内存对齐》
一,什么是对齐
1,现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问都可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问。
2,所以这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。内存对齐又分为自然对齐和规则对齐。
3,对于内存对齐问题,主要存在于struct和union等复合结构在内存中的分布情况,许多实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们要求这些数据的首地址的值是某个数M(通常是4或8);
4,对于内存对齐,主要是为了提高程序的性能,数据结构,特别是栈,应尽可能在自然边界上对齐,经过对齐后,cpu的内存访问速度大大提升。
二,自然对齐
1,指的是将对应变量类型存入对应地址值的内存空间,即数据要根据其数据类型存放到以其数据类型为倍数的地址处。例如char类型占1个字节空间,1的倍数是所有数,因此可以放置在任何允许地址处,而int类型占4个字节空间,以4为倍数的地址就有0,4,8等。编译器会优先按照自然对齐进行数据地址分配。
三,规则对齐
1,以结构体为例就是在自然对齐后,编译器将对自然对齐产生的空隙内存填充无效数据,且填充后结构体占内存空间为结构体内占内存空间最大的数据类型成员变量的整数倍。
四,决定 "字节对齐" 的因素
1,系统的位数和指定的字节对齐长度决定着数据实际所占用的内存空间大小。
2,系统的位数决定的是基本数据类型的所占内存空间。
数据类型 | 16位系统 | 32位系统 | 64位系统 |
---|---|---|---|
char | 1字节 | 1字节 | 1字节 |
char* | 2字节 | 4字节 | 8字节 |
short int | 2字节 | 2字节 | 2字节 |
int | 2字节 | 4字节 | 4字节 |
unsigned int | 2字节 | 4字节 | 4字节 |
float | 4字节 | 4字节 | 4字节 |
double | 8字节 | 8字节 | 8字节 |
long | 4字节 | 4字节 | 8字节 |
long long | 8字节 | 8字节 | 8字节 |
unsigned long | 4字节 | 4字节 | 8字节 |
3,字节对齐长度决定着数据按规则排布时填充的字节个数。
五, "字节对齐" 的规则
1,对齐字节 由 #pragam pack (n)中指定的数 n 和 这个数据结构中最大的数据成员的字节大小 中 较小 的那个数决定。
2,填充后的数据结构的总的所占内存空间 为 第1条中的对齐字节数的整数倍。
3,数据结构中数组成员的对齐的长度是按照数组元素类型的长度来比对的。
4,指定对齐长度长于struct中的类型长度最长的值时,指定的这个对齐长度等于无用。
六, 实例分析
#include<stdio.h> #pragma pack(8) typedef struct Mystruct7{ char a; // 1 char d; // 1 short b; // 2 short c; // 2 }S7; typedef struct Mystruct9{ // 4字节 8字节 char a; // 1+3 1+7 double b; // 8 8 short c; // 2 2 char d[9]; // 9+1 9+1 int e; // 4 4 // 28 32 }S9; typedef struct Mystruct10{ // 四字节 八字节 char a; // 1+3 1+7 double b; // 8 8 short c; // 2 2 char f; // 1+1 1+1 short d[5]; // 10+2 10+2 int e; // 4 4+4 // 32 40 }S10; int main() { //测试结构体对齐 #if 1 //s7长度为6,是该结构体中最长数据类型short -> 2的整数倍 //min(指定对齐长度为8/4,结构体中最长数据类型short为2),取较小值为最终对齐长度 printf(" sizeof(S7) = %d \n",(int)sizeof(S7)); //指定4字节 和指定8字节 都为 6 //按四点规则分析 printf(" sizeof(S9) = %d \n",(int)sizeof(S9)); //指定4字节 为 28 指定8字节 为 32 //按四点规则分析 printf(" sizeof(S10) = %d \n",(int)sizeof(S10));//指定4字节 为 32 指定8字节 为 40 #endif } #pragma pack()