自定义类型:结构体,联合体

一.结构体的内存管理

1.结构体的对齐规则

a.结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的位置处

b.其他成员需要对齐到是偏移量的整数倍的位置处

注意,偏移量对于不同的编译器来说不同,vs默认值为8,gcc为成员本身的字节数

c.对齐数:默认偏移量与成员大小中较小的一个数

d.结构体最终的大小应为最大对齐数的整数倍

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

以该代码为例,结构体s的存储可以下图表示

我们默认第一个成员s1位置存在0处,存下一个成员int i时需要从4的倍数处开始存,以此类推,结构体s的大小应为9个字节吗?事实并非如此,最终应为最大对齐数4的倍数,即12个字节。

e.如果嵌套了结构体,则嵌套的结构体成员对齐到自己成员的最大对齐数的整数倍处,结构体的大小为包含嵌套结构体在内成员的最大对齐数的整数倍。

下面举例说明。

struct S3
{
	double d;
	char c;
	int i;
};
struct S4
{
	char c1;
	struct S3;
	double d;
};

求结构体S4的大小,其结果为32,过程如图

包括嵌套strcut3成员在内,最大对齐数应为double类型,即8,因此嵌套结构体也从它成员最大对齐数的倍数开始存。

2.结构体内存对齐的必要性

a.平台原因:并不是所有平台都能够访问任意数据的任意地址,否则会抛出硬件异常

b.性能原因:若所有数据在内存中都连续存储,可能会产生下一个数据会存在上一个数据未使用完的空间中,导致读取数据时进行两次内存访问,浪费了运行时间

总的来说,结构体的内存对齐是用空间时间

3.既满足节省空间,又满足节省时间的方法

建议1:将较小空间的数据排在一块定义(无所谓前后)

建议2: 有一种方法可以做到同时满足节省空间和时间——修改默认对齐数

#include<stdio.h>
#pragma pack(1)//设置默认对齐数为1
struct S
{
	char c1;
	int i;
	char c2;
};
#pragma pack()//恢复默认对齐数

这里修改的默认对齐数一般为2的次方数

二.结构体的传参

struct S
{
	int arr[100];
	int n;
	double d;
};
void print1(struct S tmp)
{
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", tmp.arr);
	}
	printf("%d ", tmp.n);
	printf("%lf \n", tmp.d);
}
void print2(struct S* ps)
{
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("%d ", ps->n);
	printf("%lf \n", ps->d);
}
int main()
{
	struct S s = { {1,2,3,4,5},6,3.14 };
	print1(s);
	print2(&s);
	return 0;
}

采用print1,print2打印结构体,哪种更好?

显然是print2.

当我们使用print1进行打印,结构体有多大,print1函数中传入的tmp就有多大,这样造成了时间和空间上的双重浪费。

当我们使用print2进行打印,将结构体的地址传入函数,节省了空间。

结论:结构体传参,最好传结构体的地址。

三.结构体的位段

1.什么是位段

a.位段的“位”指的是二进制位,冒号之后的数字代表的是二进制位的数目,如_a类型只有两个二进制位,只能表示0,1,2,3的十进制数字

b.结构体实现位段,位段和结构体的声明类似,其形式如下:

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

此时的A就是一个位段类型。

那A所占内存大小是多少呢?

答案是8个字节(64个bit位)

由此看来,位段是一种专门用来节省空间的方法。

2.位段的内存分配

a.位段成员的类型只能是int, unsigned intsigned int

b.位段在空间上是需要按照四个字节(int)或者一个字节(char)来开辟的

c.位段使用有一定风险,其跨平台属性较差

struct A
{
	char _a : 2;
	char _b : 4;
	char _c : 5;
	char _d : 4;
};

下面举个例子:

我们为上面的_a,_b类型开辟一个空间

可以看到在当前环境下数据是从右向左存储的。此时我们开辟的第一块空间,不足以存放_c的数据,是直接浪费,还是继续使用剩下的并重新开辟呢?

在vs上,此时选择浪费,重新开辟一块空间。以此类推。此时浪费掉的空间bit位会填入0.

在进行数据存储时,会发生数据截断。

3.位段的风险

a.在不同机器上,位段的最大数目并不固定,36位和64位机器上为32bit位,而在更早的16位机器上,则为16bit位

b.使用位段时内存从左向右还是从右向左分配并不确定

c.int位段是有符号还是无符号并不确定

d.当一个结构包含两个位段,第二个位段成员较大时,是继续使用上一个的空间还是直接浪费依然不确定

4.位段的应用

在网络协议中,IP数据报的格式,其中很多属性值只需要很小的几个bit位就可以描述,不仅能达到想要实现的效果,还能节省空间,对于数据报的传输有利,而且有利于网络的通畅。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值