结构体的大小是大于等其成员内存的,这是因为结构体内存的确定要遵循结构体内存对齐,接下来我会讲解如何确定结构体内存。
法则
1. 第一个成员在与结构体变量偏移量为0的地址处。
讲解: 与起始地址偏离几个字节,偏移量为几。也可以这么理解,确定结构体内存就如同用 char arr[] 的数组搭积木一般,根据需要 从 下标为 0 的元素一个一个搭建,因为1偏移量代表与起始地址偏离1个字节,所以偏移量 n就代表了当前所用到的元素的下标,当然并不是成员需要多少内存,我们就搭多少,具体搭多少这是由后面3个法则决定,我们举个例子来讲解。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
(VS中默认的值为8,数组的大小只看其形式如 int arr [10],与编译器默认对齐数相比时取4,即int的大小,10个元素一个一个储存)
讲解:简单来说就是该结构成员的储存地址必须能被其对齐数整除,若当前地址不满足,这往后寻找最小的有能被结构体成员偏移量整除的地址。这里我们举一个简单例子来理解。
#include<stdio.h>
struct s {
char a;
int b;
};
int main()
{
struct s a1;
int size;
size = sizeof(a1);
printf("结构体a1的大小为:%d\n", size);
return 0;
}
运行结果:
由程序我们可知结构体a1有两个成员分别是 char a与 int b;他们两个的大小和为5但是结构体大小确为8。这是为什么?下图揭示了结构体成员的储存方式。
右边数字代表偏移量,一个格子代表一个字节的内存,现在我们根据法则一,二来模拟一下结构体内存的确定。(编译器默认对齐数为8)
首先我们第一个要存放的成员为char a 大小为1。由于1<8,所以,char a的对齐数为。接下来确定它储存的位置。由于它是第一个元素所以存放在偏移量为0的地址处,即为红色区域。我们第二个存放的成员是int b,4<8由此可得出它的对齐数为4。接下来我们确定int b的储存位置。根据法则二我们可知 偏移量为1 ,2,3的地址不符合储存条件,跳过(能被对齐数整除),唯一符合条件的只有偏移量为4的地址。因此int b 储存在偏移量为4到偏移量为7的地址所指向的内存中,也就是红色区域。而跳过的则是蓝色区域.
我们可以总结出目前确定结构体成员存储位置的流程:确定该成员的对齐数->判断当前位置地址的偏移量是否能被对齐数整除,不能则跳过,向后面寻找
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
讲解:理解法则一,二后这个法则很好理解,我们只需要举出一个简单的例子,如下。
#include<stdio.h>
struct s {
char a;
int b;
char c;
};
int main()
{
struct s a1;
int size;
size = sizeof(a1);
printf("结构体a1的大小为:%d\n", size);
return 0;
}
运行结果:
其储存结构如下:
存放完 char a, int b后结构体的大小为8最大对齐数为4,存放完char c后结构体大小为9但是最大对齐数为4,由法则3可知结构体的大小必须为最大对齐数的整数倍,所以要将结构体的大小补到12(4的倍数)。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
讲解:上例子!
#include<stdio.h>
struct s {
char a;
int b;
char c;
};
struct s1 {
short d;
char f;
struct s sp;
};
int main()
{
struct s a1;
struct s1 a2;
int size;
int size1;
size = sizeof(a1);
size1= sizeof(a2);
printf("结构体a1的大小为:%d\n", size);
printf("结构体a2的大小为:%d\n", size1);
return 0;
}
运行结果如下:
结构体s1除去其结构体成员,剩下的成员里找出最大对齐数——short d 最大对齐数为2,结构体而s1中结构体成员sp的最大对齐数为4,由法则三可得最终结构体的大小得同时为2 ,4的倍数!!
讲解结束,有问题可留言。