引言
我们先来看下下面的代码:
#include <stdio.h> typedef struct { unsigned char a; unsigned int b; unsigned char c; } debug_size1_t; typedef struct { unsigned char a; unsigned char b; unsigned int c; } debug_size2_t; int main(void) { printf("debug_size1_t size=%lu,debug_size2_t size=%lu\r\n", sizeof(debug_size1_t), sizeof(debug_size2_t)); return 0; }
首先我们来计算一下对于size1 其中变量a,1byte,b,4byte,c,1byte总共六比特(32位系统下)
debug_size1_t size=12,debug_size2_t size=8这是为什么呢?
深入探究
从网上查找资料后发现,对于结构体内存空间的分布,有下面这个计算公式:
结构体大小 = 末尾成员偏移量+末尾成员大小+末尾填充字节数
Tips 偏移量:这里可以简单理解为结构体内成员变量的地址距离结构体首地址的相地指数的大小。
我们来看一下下面这段代码:
struct perInfo1{ int num; // 4 bytes char name[10]; // 10 bytes double account; // 8 bytes }; struct perInfo1 Tony1 = {1,"Tony",3.14159};
-
首先计算机为变量num分配四个字节内存,它是结构体的首地址,不发生偏移,如下图所示(假设这是内存中的地址空间):
-
下面我们再来看结构体的第二个变量name,它由十个char类型组成,由于结构体变量在做字节对齐的时候有一个规则:每个成员相对于结构体首地址的偏移量必须是当前成员所占字节数的整数倍
,如果不是的话,操作系统会自动补齐。对于变量name,如下图所示:
-
下面为account分配空间,由于double类型占用空间为8字节,而当前为14字节,不是8的整数倍,因此需要分配空间自动补齐。
填充之后再为account分配空间:
-
在结构体定义完成之前,还会进行以下判断,当前结构体的总大小是否为其最宽成员所占内存大小的整数倍,这也就是为什么perInfo的大小是32而不是30的原因了。(account长度最长为8字节,所以要扩充到其整数倍即32)
一直到这里我们就可以解释文章开始的例子中sizeof的判断出错的问题了
- 1.debug_size1_t 存储空间分布为a(1byte)+空闲(3byte)+b(4byte)+c(1byte)+空闲(3byte)=12(byte)。
- 1.debug_size2_t 存储空间分布为a(1byte)+b(1byte)+空闲(2byte)+c(4byte)=8(byte)。
总结
注意结构体分配空间时
-
每个成员相对于结构体首地址的偏移量必须是当前成员所占字节数的整数倍
- 当前结构体的总大小是否为其最宽成员所占内存大小的整数倍
*文章参考https://blog.csdn.net/ShyLoneGirl/article/details/83049651 https://www.runoob.com/cprogramming/c-structures.html
欢迎关注公众号 树语星球
学到了!