我们在计算一个数据类型所占的内存大小时,通常会用sizeof()来计算,例如计算整形、浮点型、数组大小等。但当一个结构体中还有多种数据类型他的大小是怎么计算的呢?
当我们想计算一个如下结构体的大小时。
struct s1
{
int a;
char b;
};
这里需要遵守以下规则。
1、结构体的第一个成员永远放在0偏移出。(这里的偏移量是指相对于起始位置的。)
2、从第二个成员开始,以后每个成员都要对其到某个对齐数的整数倍处,这个对齐数是:成员自身大小和默认对齐数的较小值。(注:VS环境下默认对齐数是8,gcc环境下没有默认对齐数,没有默认对齐数时,对齐数就是成员自身的大小。以下都是按照VS的环境来讲的。)
3、当成员全部放进去后,结构体的总大小必须是所有成员的对齐数中最大对齐数的整数倍。如果不够,则浪费空间对其。
a是第一个成员放在0偏移处,占4个字节的大小,b的自身大小是1,而默认对齐数是8取较小值就是1,放在a紧跟后面,现在占了5个字节的大小,不是所有成员最大对齐数的整数倍,这里的最大对齐数是4,所以要是他的整数倍就要舍去3个空间,所以这个结构体的大小是8个字节。
以上就是计算结构体大小的基本逻辑。
下面举几个例子加深印象。
struct s1
{
int a;
char b;
short c;
short d;
};
计算上面这个结构体的大小。
a是第一个成员在0偏移处,b的对齐数是1紧跟在a后面,c的对齐数是2要在偏移量是2的倍数处所以舍去一个空间在偏移量为6的地方,d的对齐数是2也要放在对齐数2的倍数的位置。此时所有成员占了9个字节的空间,总大小要是最大对齐数4的整数倍也就是12,所以要舍去3个字节的空间。
#define MAX_SIZE A+B
struct _Record_Struct
{
unsigned char Env_Alarm_ID : 4;
unsigned char Para1 : 2;
unsigned char state;
unsigned char avail : 1;
}*Env_Alarm_Record;
struct _Record_Struct *pointer = (struct _Record_Struct*)malloc(sizeof(struct _Record_Struct) * MAX_SIZE);
当A = 2,B = 3时,pointer分配()字节的空间。
首先要计算这个结构体的大小,这个结构体是一个位段,先开辟1个比特位,Env_Alarm_ID占4个比特位,Para1占2个比特位,以后的state就不够用了再开辟一个字节的空间,avail占用1个比特位,不够用再开辟一个字节,剩下的7个比特位浪费掉。总共开辟了3个字节的空间。由于MAX_SIZE是直接把A+B替换过来,A是2B是3,pointer分配的空间就是3*2+3=9。