结构体内存对齐与位段


前言

提示:仅供参考


一、结构体内存对齐

1.什么是结构体内存对齐?

编译器在计算结构体大小时,发生内存对齐
如:

struct s{
	char c;
	int i;
};
int main(){
	printf("%d\n",sizeof(struct s));
	return 0;
}

问:程序的结果是多少?
char 一个字节;int 4个字节
1+4=5 ?
答案是 8。

2.内存对齐的规则:

a. 第一个成员偏移量为0。
b. 其他成员要在(偏移)对齐数的整数倍。
对齐数:编译器默认对齐数与成员变量大小中的较小值
c. 结构体的总大小是成员中最大对齐数的整数倍。
d. 若有结构体嵌套,内结构体对齐自己的最大对齐数整数倍偏移量,外结构体整体大小是所有最大对齐数的整数倍(含内结构体成员的对齐数)

举例说明更形象化:如

struct s{
	char c;	 /大小为1, 默认对齐数为8,取1作为对齐数
	int i;	/大小为4  ,默认对其数为8,取4作为对齐数,在4的倍数偏移处开始存储
};
int main(){
	printf("%d\n",sizeof(struct s));
	return 0;
}

第一个成员char 与结构体的偏移量为0,即占据了第一个字节。
第二个成员int 大小是4字节,vs平台下默认对齐数是8 ,取较小值 4 作为此成员的对齐数,->即变量 i 要在偏移为4的整数倍地址处开始存储 往后存4个字节:内存图:
在这里插入图片描述

3.为什么存在结构体内存对齐?

α. 平台原因:并非所有硬件平台都能访问任意地址上的任意数据;某些硬件平台只能在特定地址上取值特定类型的数据。
β. 性能原因:数据结构应该尽可能在自然边界上对齐,原因在于,访问未对齐内存时,某些数据需要处理器访问两次才能得到完整数据,而对齐的内存仅需一次。

内存对齐 - -> 空间换时间。

4.vs平台下如何修改默认对齐数?

a. 预编译命令:#pragma pack(num)
修改编译器默认对齐数为num个字节
b. pack不带参数,则恢复平台默认对齐数

#pragma pack(4) /将默认对齐数修改为4字节
#pragma pack() /恢复默认对齐数为平台默认对齐数

二、位段

1.什么是位段?

位段的声明与结构体类似
语法为:

struct A{
	int a:2;
	int b:5;
}

2.位段的实现:

α. 位段成员必须是int、unsigned int、char。
β. 位段成员后有一个冒号和一个数字。数字表示分配几个bit位

3.位段存在的意义

在一定程度上节省空间

4.vs平台下位段中内存的使用形式

a. 在空间上以4字节(int)或1字节(char)方式来开辟。
b. 前一个空间剩余的bit位不够时,直接浪费,使用新开辟空间的bit位。
c. 一个字节内部从低位向高位使用。

5.位段存在的问题:

C语言标准并未规定上一个空间没用的bit位能否下一个空间继续使用;因此各个编译器都有自己的实现。
位段最大的问题是跨平台的问题:
a. int位段不确定有无符号。
b. 位段中最大位数不确定.
c. 位段的成员在内存中分配方式不确定.
d. 当一个结构含两个位段,第二个位段大于第一个位段余留的空间时,余留空间是舍是用不确定。

总结:

在编写程序时,考虑到结构体存在内存对齐,可以将结构体中的成员变量合理安排位置,使程序所需内存空间得到有效利用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值