其他分享
首页 > 其他分享> > 自定义类型:结构体、枚举、联合

自定义类型:结构体、枚举、联合

作者:互联网

一、结构体
1.结构体的声明

struct tag
{
     member-list;
}variable-list;

例如你要描述一个学生:

struct stu
	{
		char name[20];
		int age;
		char sex[5];
		char id[20];
	}x,y;    //声明类型的同时定义变量x,y

2.结构体的自引用(结构体中有一个自身结构体变量)

struct Node
{
	int data;
	struct Node* next;    //自引用用指针
};

3.结构体变量的定义以及初始化
(1)结构体变量的定义

struct Point
{
	int x;
	int y;
}p1;         //声明类型的同时定义变量p1
struct Point p2;     //定义结构体变量p2

(2)结构体变量的初始化

struct stu
{
	char name[20];
	int age;
	char sex[5];
};
struct stu s = { "wangwenqian", 18, "女" };  //初始化
struct Point
{
	int x;
	int y;
};
struct Node
{
	int data;
	struct Point p;
	struct Node* next;
}n1 = { 10, {4,5},NULL };    //结构体嵌套初始化

4.结构体内存对齐 (重点)
结构体的内存对齐问题,实际上就是结构体类型所占空间的大小问题。

struct s1
	{
		char c1;
		int i;
		char c2;
	};
	printf("%d\n", sizeof(struct s1));

按照我们正常的思路,这个结构体的大小就是其结构体内所有类型相加的大小,即1+4+1=6.那我们把程序运行一下,看看它的结果。在这里插入图片描述
结果却是12.看到这里,我们脑子里自然会有这样的结论:结构体在内存中的存储是有自己的规则的。
我们通过画图来更直观的看一看:

struct s1
{
          char a;
          int i;
};

在这里插入图片描述
如上图所示,在没有结构体对齐的情况下,CPU读取a时直接从地址0处开始读取一字节。在读取b时,CPU先从偏移量为1的地址处先读b的前三个字节,再从偏移量为4的地址处读取b的最后一个字节。此中,仅仅是b我们CPU就读取了俩次,如果这样的b还有很多,都需要CPU去多次的访问内存,那读取数据的速度就会大打折扣。实质上也是为了我们访存的效率着想。

为什么存在内存对齐?
1.平台原因:不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2.性能原因:数据结构(尤其是栈)应该尽可能的在自然边界上对齐。原因在于,为了访问未对其的内存,处理器需要作俩次内存访问;而对齐的内存访问仅需要一次访问。

结构体的内存对齐是拿空间来换取时间的做法。

那在内存对齐的情况下,我们是怎样访存的呢?话不多说,上图。
在这里插入图片描述
我们得到结构体的对齐规则
(1)第一个成员在与结构体变量偏移量为0的地址处。
(2)其他成员变量要对齐到某个数字(对其数)的整数倍的地址处。
对齐数 = 指定的一个对齐数 与 该成员大小的较小值。
(3)结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整倍数。
(4)如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整倍数处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的最大对齐数)的整数倍。

那么设计结构体时,我们既要满足对齐,又要节省空间,就要做到:让占用空间小的成员尽量集中在一起。

5.位段
位段的声明和结构体是类似的,但有俩个不同:
(1)位段的成员必须是int、unsigned int 或 signed int。
(2)位段的成员名后边有一个冒号和一个数字。

比如:

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
	//a冒号后面的数字表示使用a的俩个字节
};

位段的内存分配:
1.位段的成员可以是int 、unsigned int、signed int 或者是 char (属于整形家族)类型。
2.位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的。
3.位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

位段不考虑效率,但是可以很好的节省空间。

6.枚举
枚举顾名思义就是一一列举。把可能的值一一列举。(常量)
注意列举的常量需用逗号一一隔开。
枚举不用考虑内存对齐,可以赋初值。枚举的值默认从0开始,往后依次递增。

enum Sex
{
	MALE=1,
	FEMALE=3,
	SECRET=6
};
enum Day
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};

Day里的变量的值分别为0,1,2,3,4,5,6,7,8,9。

7.联合(共用体)
联合体是一种特殊的自定义类型,这种类型定义的变量也包含一系列的成员,特征是这些成员公共用一块空间(所以联合也叫共用体)。比如:

union Un
{
	char c;
	int i;
};

联合体内存共享,其内部所有成员都是联合体的第一个成员,即所有成员的地址都是一样的。联合体变量的大小至少是最大成员的大小,至少要有能力保存最大的那个成员。

标签:char,struct,自定义,int,位段,枚举,类型,对齐,结构
来源: https://blog.csdn.net/qq_43632625/article/details/94596505