以下内容摘自此处:
作者:太平小小草
链接:https://www.jianshu.com/p/e772fff47465
来源:简书
结构体大小计算有三个原则:
一,结构体变量的首地址,必须是结构体 "最宽基本类型成员" 大小的整数倍(0被认为是任何数的整数倍)。
二,结构体每个成员相对于结构体首地址的偏移量,都是该成员的整数倍。
三,结构体的总大小,为结构体 “最宽基本类型成员” (将嵌套结构体里的基本类型也算上,得出的最宽基本类型) 大小的整数倍。
个人理解其中最宽基本类型成员:指的就是占字节数最大的类型成员。下面给出一个表格,方便查看各个类型的字节数:
下面给出一些计算结构体大小的例子:
1.简单结构体
1.1
struct s1{
char ch1;
char ch2;
int i;
};
这个结构体的大小容易计算,为8。ch1和ch2共同占4字节,i占4字节,共8字节。
1.2
struct s1{
char ch1;
int i;
char ch2;
};
这个和上面哪个只是结构体成员顺序换了一下,但大小就变成了12。是因为要满足偏移量是成员的整数倍,ch1偏移量是0,i的偏移量不可能是1,因为1不是i(大小4)的倍数,所以i的偏移量是4,ch2的偏移量就变为了8,加ch2是9,要满足结构体大小是成员大小整数倍,就是12。
2.成员包含数组的结构体
2.1
struct s2{
char ch;
int i;
char str[10];
};
这个结构体的大小是20,先看前两个成员,大小是8,毋庸置疑,这个char类型的数组,只需要把它看做十个char连在一起即可,加起来就是18,再满足结构体大小为成员整数倍,所以大小就是20。
含数组成员A array[n],就把这个数组看成n个A类型的数据连在一起即可。
3.嵌套结构体的结构体
3.1
struct s3{
char ch;
int i;
struct s{
char ch1;
int j;
}sub;
float f;
};
里面这个结构体的大小是8,那么是否结构体大小就要向8对齐呢?这个结构体的大小是20,很明显不是8的倍数。所以计算结构体大小时是把里面这个结构体就看做是一个char,和一个int,不是看做一个整体。
最宽基本类型成员是j (4位),则
ch占4个字节,i占4个,ch1占4个,j占4个,f占4个,一共20。
3.2
struct s3{
char ch;
char i;
struct s{
char ch1;
int j;
}sub;
char f;
};
注意这里结构体(s3)里的结构体(s)内的数据并不能与之前的数据进行内存对齐。
s里面的ch1与上面的ch,i不能共同占用4个字节,得另外开辟4个字节内存。这点需要注意一下。故大小为4+4+4+4=16而不是4+4+4=12。
3.3
struct s3{
char ch;
char i;
struct s{
char ch1;
double j;
}sub;
char f;
};
最宽基本类型成员是j (8位),则
ch和i共占8个字节,ch1占8个,j占8个,f占8个,一共32。
4.成员包含联合体的结构体
4.1
struct s5{
char ch;
int i;
union{
char ch1;
int j;
};
};
联合体大小就是成员中最大类型的大小,所以这个结构体大小是12.
4(ch)+4(i)+4(j)=12。
5.指定对齐值
指定对齐值:#pragma pack(n) //指定向n对齐
#pragma pack(n) 若以 #pragma pack()
作结束,表示该种对齐方式至此为止。
5.1对齐值小于最大类型成员值
#pragma pack(4) //指定向4对齐 最大是8
struct s6{
char ch;
int i;
float f;
double d;
};
如果我们没有指定对齐值,这个结构体大小是8(ch、i)+8(f)+8(d)=24,我们指定向4对齐,所以大小是4的倍数,所以结构体大小是4(ch)+4(i)+4(f)+4(d)+4(d)=20。
5.2对齐值大于最大类型成员值
#pragma pack(10) //指定向10对齐 最大是8
struct s7{
char ch;
int i;
float f;
double d;
};
我们指定的对齐值是10,最大为8,是否就向10对齐?不是,当指定对齐值大于自身对齐值时,向自身对齐值对齐,大小是24,即8(ch、i)+8(f)+8(d)=24。