内存对齐、结构体大小

内存对齐

计算机在读取数据时,如果一次读取一个字节,读取一个四字节的数据就需要读取 4 次,实际上,有可能的读取字节数是1,2,4,8,16,以一次读取2个字节为例,也就是说,所有的数据都是两个字节相当于一个读取单位。

0123
0123

在我们看来,计算机能从任意位置处开始读取数据,实际上,在以两个字节为例的情况下,并不是这样的,而是只能直接读取以0和2开始的两个字节的数据,就是认为0和1是一个读取的数据,2和3是一个数据,不能从1处开始读取数据。如果要读取从1开始的两个字节的数据,就需要先读取0和1,再读取2和3处的数据,进行处理后,才能够得到1开始的两个字节的数据。

结构体大小

偏移量

偏移量是结构成员相对于结构开头的字节偏移数。offsetof可以计算偏移量,在使用offsetof时,需要包含stddef.h这个头文件。
第一个成员在与结构体变量偏移量为0的地址处。其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。

#include <stdio.h>
#include <stddef.h>
struct S
{
	int n;
	double f;
};
int main()
{
	printf("%zd\n", offsetof(sruct S, n));//0
	printf("%zd\n", offsetof(sruct S, f));//8
	printf("%zd\n", sizeof(int));//4
	printf("%zd\n", sizeof(double));//8
	printf("%zd\n", sizeof(struct S));//16

	return 0;
}

该例中int占据4个字节,double占据8个字节,如果默认对齐数是4,struct S中的n的空间是0 ~ 3,f 是4 ~ 11,总共是12个字节,但sizeof(struct S)的结果是16,满足默认对齐数是8的情况,也就是说VS2022的默认对齐数是8。

结构体的大小是所有变量中最大对齐数的整数倍

struct S
{
	int n;
	char ch;
};
int main()
{
	printf("%zd\n", sizeof(struct S));//8
	return 0;
}

n的偏移量是从0 ~ 3,ch 的偏移量只有4,因为结构体是所有变量中最大对齐数的整数倍,也就是4的整数倍,所以sizeof(struct S)的结果是8。
结构题S1嵌套了结构体S2,S2的对齐数是S2的变量中的最大对齐数,S1的大小是所有最大对齐数(含S2的对齐数)的整数倍。

struct S2
{
	char ch;
	int n;
};
struct S1
{
	char ch;//0
	struct S2 s;//4~11
};

int main()
{
	printf("%zd\n", sizeof(struct S2));//8
	printf("%zd\n", sizeof(struct S1));//12
	return 0;
}

S2的对齐数是int的大小,也就是4,s的偏移量是4 ~ 11的位置,S1的大小是12。

修改默认对齐数

#pragma 这个预处理指令可以修改默认对齐数。

#pragma pack(4)
struct S1
{
	int n;
	double f;
};
#pragma pack()
struct S2
{
	int n;
	double f;
};

int main()
{
	printf("%zd\n", sizeof(struct S1));//12
	printf("%zd\n", sizeof(struct S2));//16
	return 0;
}

#pragma pack(4)将VS的默认对齐数改为了4,所以S1的大小就是12,而#pragma pack()又将VS的默认对齐数改为默认值,也就是8,所以S2的大小是16。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值