1.偏移量
在讨论结构体的字节大小之前,先说一下偏移量的概念,偏移量指的是结构体变量中成员的地址和结构体变量地址的差。结构体变量中第一个成员的地址就是结构体变量的首地址。因此,一般情况下(后续会讨论特殊情况)结构体中的第一个成员的偏移量为0,结构体的字节大小为最后一个成员的偏移量+该成员的字节大小。也就是说,和数组不一样的是,结构体的大小不是所有成员大小简单的相加,需要考虑到系统在存储结构体变量时的地址对齐问题。代码如下所示:
struct s
{
char a;
char b;
int c;
};
上述代码中定义了一个结构体s, 在结构体之中,第一个成员a的偏移量为0,第二个成员b的偏移量是第一个成员的偏移量+第一个成员的大小(0+1)其值为2,后续按照此规律,后一个成员的偏移量=上一个成员的偏移量+上一个成员的字节大小;
注意:按照此规律,第三个成员c的偏移量是第二个成员的偏移量应该是加上第二个成员的大小(2+1)其值为3,但是事实并不是这样,在实际中,存储变量时地址要求对齐,编译器在编译程序时会遵循两条原则:
**(1)结构体变量中任何一个成员的偏移量必须是该成员字节大小的整数倍(0被认为是任何数的整数倍) **
(2)结构体大小必须是所有成员大小的整数倍,即要能够整除所有成员的字节大小;
前两个成员均符合要求,但第三个成员的偏移量为3,并不是自身(int)大小的整数倍。编译器在处理时会在第二个成员后面补上1个空字节,使得第三个成员的偏移量变成4。结构体大小等于最后一个成员的偏移量加上其大小,上面的例子中计算出结构体大小为:最后一个成员的偏移量+该成员的字节大小,即4(偏移量)+4(字节大小)=8;
printf("%d\n", sizeof(struct s));//8
2.同类型不同顺序
struct ss
{
char a;
char b;
int c;
};
struct tr
{
char a;
int c;
char b;
};
结构体中成员顺序会对最终结构体的字节大小有一定影响,代码如上。
虽然结构体ss和tr中成员都一样,但sizeof(struct ss)的值为8而sizeof(struct tr)的值为12。
printf("%d\n", sizeof(struct ss));//8 printf("%d\n", sizeof(struct tr));//12
由此可见,结构体类型需要考虑到字节对齐的情况,不同的顺序会影响结构体的大小。
3.嵌套的结构体
对于嵌套的结构体,需要将其展开。对结构体求sizeof时,同时也有两个原则:
1.嵌套的结构体中,第一个成员的偏移量,必须是被嵌套的结构体中那个字节数最大的成员的整数 倍;
2.在计算有嵌套的结构体的字节时,要把其里面嵌套的结构体展开,然后按照上述相同的方法依次 计算偏移量;
struct strr
{
short i;//偏移量0
struct
{
char c;//偏移量4
int j;//偏移量8
} aa;
int k;//偏移量12
};
结构体strr的成员aa.c的偏移量应该是4(被嵌套的结构体中最大成员为int,要为int的整数倍),而不是2。整个结构体大小应该是16(12+4)
4.结构体中包含数组
struct array
{
float f;//偏移量0
char p;//偏移量4
int arr[3];//偏移量5,不满足要求,要补到8
}array;
在含有数组的结构体中,该数组偏移量要补充至该数组类型的字节整数倍,而不是数组本身的字节,例如:int arr[3]偏移量为5,不满足要求,需要补充字节,但不是补充到12,而是4的整数倍
结果是8+12=20(数组的偏移量+数组的字节数)
注意:假如,最后结构体字节数并没有能够直接整除任何一个成员,依旧要补充到能够整除所有成员字节大小为止,例如:
struct s2
{
int i; //偏移量为0
short m; //偏移量为4
};
上述代码中,第一个成员偏移量为0,第二个成员偏移量为4,均符合要求;但是,按照计算方法,最后的结构体字节数为4+2=6,6无法整除所有成员的字节数大小,所以,需要继续补充字节至8,
所以该结构体最后的字节数为8;
printf("%d\n",sizeof(struct s2));//8
版权归原作者 唯有拼搏 所有, 如有侵权,请联系我们删除。