结构体内存对齐———计算结构体总字节大小

一、规则 

 成员大小就是它的字节数,(sizeof可求)

变量要到偏移量等于它的对齐数的地方才会开始存储

二、实例 

(1)无嵌套结构体

i 例一:

解释

char 的字节大小是1,和VS默认的8相比更小,所以char的对齐数是 1,int 则是4(所有中最大的对齐数是4)

根据规则1,c1存在偏移量为0的地址。用掉第一个字节

接下来要存储 i ,因为他的对齐数是4,根据规则2. 所以浪费了3个字节,来到偏移量为4(4的倍数)的地址开始存储 i ,存储i 用掉了4个字节(从偏移量为4的地方到偏移量为7的地方)。

最后存储 c2,现在是偏移量为8的地址,是1的倍数,所以就在偏移量为8的地方存储了c2,使用1个字节

此时,存储完这3个变量,从 偏移量为1 到 偏移量为8 的地方,一共用了9个字节

根据规则3:结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍,9之后的最近的4的倍数是12,所以最后又要浪费3个字节,最后结果为12

ii 例二:

解释:

char 的字节大小是1,和VS默认的8相比更小,所以char的对齐数是 1,int 则是4(所有中最大的对齐数是4)

根据规则1,c1存在偏移量为0的地址。用掉第一个字节

接下来要存储 c2,因为他的对齐数是1,根据规则2. 现在偏移量为1(1的倍数)的地址开始存储 c2 ,存储c2用掉了第二个字节。

最后存储 i,现在偏移量为2,不是4的倍数,浪费2个字节,偏移量来到为4的地方,存储用4个字节(从偏移量为4的地方到偏移量为7的地方),用了4个字节。

此时,存储完这3个变量,从 偏移量为0到 偏移量为 7的地方,一共用了8个字节

根据规则3:结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍,8刚好是4的倍数,,最后结果为8

iii 例三

解释:

char 的字节大小是1,和VS默认的8相比更小,所以char的对齐数是 1,int 则是4,double与其相等,对齐数也就是8(所有中最大的对齐数是8)

根据规则1,d 存在偏移量为0的地址用掉8个字节(从偏移量为0处到偏移量为7处)

接下来要存储 c,因为他的对齐数是1,根据规则2. 现在偏移量为8(是1的倍数).就在此存储 c 用掉了1个字节。

最后存储 i,现在偏移量为9的地址,不是4的倍数,浪费3个字节所以就在偏移量为12的地方存储了 i。存储用4个字节(从偏移量为12的地方到偏移量为15的地方)

此时,存储完这3个变量,从 偏移量为0到 偏移量为15 的地方,一共用了16个字节

根据规则3:结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍,而16刚好是8的倍数,最后结果为16

(2)有嵌套结构体

例:

 解释:

char 的字节大小是1,和VS默认的8相比更小,所以char的对齐数是 1,double则是8,被嵌套的结构体成员⾃⼰的成员中最⼤对⻬数也为8

则所有中最大的对齐数是  8(含被嵌套结构体中成员的对⻬数)

根据规则1,c1存在偏移量为0的地址。用掉第一个字节

接下来要存储 struct S s,因为他的对齐数是8,

根据规则4(如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处.

现在偏移量为1(不是8的倍数),浪费7个字节,偏移量来到为8的地方的地址开始存储 struct S ,存储用掉了16个字节(从偏移量为8的地方到偏移量为23的地方)

最后存储 d,现在偏移量为24,(是8的倍数),存储用8个字节(从偏移量为24的地方到偏移量为31的地方)

此时,存储完这3个变量,从 偏移量为0到 偏移量为 31的地方,一共用了32个字节

根据规则4: 结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍
32刚好是8的倍数,,最后结果为32

三、计算结构体相对起始位置的偏移量函数

1.函数介绍

 头文件  #include<stddef.h>

返回值:size_t  无符号整形  ( %u  打印无符号数)(这里建议用%zu)

参数:struct Name  结构体名,member Name 成员名

2、实例

#include<stddef.h>
struct S1
{
	char s1;
	int i;
	char c2;
};

struct S2
{
	char c1;
	char c2;
	int i;
};

struct S3
{
	double j;
	float k;
	char m;
};

int main()
{
	printf("%zu\n", offsetof(struct S1, s1)); //0
	printf("%zu\n", offsetof(struct S1, i)); //4
	printf("%zu\n", offsetof(struct S1, c2)); //8
	printf("\n");
	printf("%zu\n", offsetof(struct S2, c1)); //0
	printf("%zu\n", offsetof(struct S2, c2)); //1
	printf("%zu\n", offsetof(struct S2, i)); //4
	printf("\n");
	printf("%zu\n", offsetof(struct S3, j)); //0
	printf("%zu\n", offsetof(struct S3, k)); //8
	printf("%zu\n", offsetof(struct S3, m)); //12
}

一个变量偏移量是多少,那么就在那个位置的字节数开始存储它

四、修改对齐数

括号里面应该是2的次方(也就是偶数,但还有2的0次方——1)

当括号里是1,就是取消对齐了

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值