自定义类型:结构体、枚举、联合
作者:互联网
一、结构体
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