C语言 ——— 结构体内存对齐

目录

发现问题

 偏移量宏:offsetof()

结构体内存的对齐规则

小结 


发现问题

有以下两个结构体:

结构体1:

struct S1
{
	char c1; // 1字节
	int i; // 4字节
	char c2; // 1字节
};

结构体2:

struct S2
{
	char c1; // 1字节
	char c2; // 1字节
	int i; // 4字节
};

通常情况下:结构体1的大小是6字节(char是1字节 + int是4字节 + char是1字节);结构体2的大小是6字节(char是1字节 + char是1字节 + int是4字节)

打印结构验真假:

打印发现 结构体1 和 结构体2 所占内存空间的大小并不一样,出现这种结果的原因是因为结构体内存对齐规则的原因,利用宏 offsetof() 可以帮助判断


 偏移量宏:offsetof()

offsetof()  这个宏可以计算结构体成员相较于结构体起始位置的偏移量

头文件为:#include<stddef.h>

计算结构体所有成员对于结构体起始位置的偏移量: 

struct S1
{
	char c1;
	int i;
	char c2;
};
int main()
{
	printf("%d", offsetof(struct S1, c1));
	printf("%d", offsetof(struct S1, i));
	printf("%d", offsetof(struct S1, c2));
	return 0;
}

计算结果:

可以发现,c1 是char类型的变量,所占内存空间只有1个字节,且是第一个变量,所以放在结构体起始位置偏移量为0的地方,那为什么第二个变量要放在离起始位置偏移量4的地方,中间的3个字节为什么要浪费掉?

由以上问题分析得出,结构体成员不是按照顺序在内存中连续存放的,是有一定的对齐规则


结构体内存的对齐规则

1. 结构体的第一个成员永远放在相较于结构体起始位置的偏移量为0的位置

2. 从第二个成员开始,往后的每个成员都要对齐到某个对齐数的整数倍处

3. 结构体的总大小,必须是最大对齐数的整数倍,而这最大对齐数也就是结构体所有成员的对齐数中最大的值

对齐数:结构体成员自身的大小和默认对齐数的较小值

默认对齐数:VS编译器上的默认对齐数是8,而gcc这种编译器没有默认对齐数,对齐数就是结构体成员的自身大小 

由以上的规则,我们可以得知,为什么第二个变量要放在相较于结构体起始位置的偏移量为4的位置了

再次复盘以上结构体:

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

第一个成员:char类型的c1变量,放在相较于结构体起始位置的偏移量为0的位置

第二个成员:int类型的i变量,i的大小是4个字节,VS中默认对齐数是8,在4和8中取较小值,也就是4,所以第二个成员变量 i 要放在偏移量为4的倍数处,所以成员变量 i 的偏移量是 4

第三个成员:char类型的c2变量,c2 的大小是1个字节,在1和8中取较小值,也就是1,所以第三个成员变量 c2 要存放在偏移量为1的倍数处,且偏移量为4、5、6、7的位置已经被第二个成员所占,所以 c2 存放在偏移量为8的位置

结构体总大小: 

printf("%d\n", sizeof(struct S1));

结构体的总大小是最大对齐数的整数倍,由以上第二个成员可得出,最大对齐数是4,所以结构体的总大小必须是4的倍数,而当前结构体的大小是9,因为第三个成员是放在偏移量为8的位置的,且占一个字节,所以一共占了9个字节,9不是4的倍数,所以最4的最小整数倍是12,所以最后整个结构体的总大小是12个字节


小结 

除了结构体的第一个成员是放在结构体的起始处位置(也就是相较于结构体起始位置偏移量为0的位置),其他的成员要按照对齐规则存放

且结构体的总大小是结构体成员最大对齐数的整数倍

C语言中,结构体内存对齐是一种优化手段,用于提高内存访问效率和减少内存浪费。结构体内存对齐规则是根据结构体成员的类型和顺序,以及编译器的对齐方式来确定的。 根据引用中的例子,我们可以看到结构体s1和s2的成员顺序相同,但是它们的内存对齐结果却不同。结构体s1的大小为8字节,结构体s2的大小为12字节。这是因为编译器在对齐结构体时,会根据最大成员的大小来确定对齐方式。在结构体s1中,最大成员是int类型的c,大小为4字节,所以结构体s1的对齐方式是4字节对齐。而在结构体s2中,最大成员是char类型的b,大小为1字节,所以结构体s2的对齐方式是1字节对齐。 另外,根据引用的例子,我们可以看到结构体s2中嵌套了结构体s1。通过使用offsetof函数,我们可以得到结构体s2中成员a和成员c的偏移量分别为0和4字节,这表明结构体s2中的成员是按照其在结构体中的声明顺序进行排列的。同时,结构体s2的大小为12字节,这是因为结构体s2的对齐方式是最大成员char类型b的大小1字节。 总结起来,C语言结构体内存对齐是根据结构体成员的类型和顺序,以及编译器的对齐方式来确定的。这种对齐可以提高内存访问效率和减少内存浪费。不同的结构体可能有不同的对齐方式和大小,这取决于结构体中最大成员的大小和结构体中的成员顺序。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [【C语言系列】-结构体中的内存对齐](https://blog.csdn.net/m0_64332179/article/details/122682708)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [【C语言】——结构体进阶:结构体内存对齐(超详细)](https://blog.csdn.net/luoheng1114/article/details/127106154)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值