一、结构体:
1.结果体是一些值的集合,这些值称为成员变量。结果的每个成员可以是不同类型的变量,可以是数组,指针,甚至其他结构体
2.结构体的声明:
struct Stu
{
char name[20];
int age;
char sex[5];
};
3.特殊的声明:不完全声明
struct
{
int a;
char b;
float c;
}x;
//省略结构体名称,直接定义结构体变量
struct
{
int a;
char b;
float c;
}*p,arr[20];
//省略了结构体名称,直接定义结构体指针,结构体数组
//p = &x ; 是否合法?
警告:编译器会把上面的俩个声明当成完全不同的俩个类型,所以这样的赋值不合法
4.结构体成员的访问
- 结构体变量的成员是通过点操作符(.)来访问的
- 结果体指针的成员是通过->来访问的
5.结构体的内存对齐
- 内存对其的原则:
1.第一个成员在与结构体便宜了为0的地址处
2.其他成员变量要对其到对其数的整数倍的地址处
对齐数 = min(编译器默认的对其数,该成员的大小)
vs默认的值:8
Linux默认的值:4
3.结构体的总大小为最大对齐数的整数倍
最大对齐数:几个对齐数中最大的
4.如果有嵌套结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
- 为什么存在内存对齐?
1.平台原因
并不是所有的硬件都能任意的访问任意地址上的任意数据,编制并不是对所有的内存进行编制,所以有些内存不能访问
2.性能原因:
数据结构一个尽可能地在自然边界上对齐
如果访问未对齐的的内存,处理器需要做俩次内存访问,而对齐的内存访问仅仅需要一次
结构体的内存对齐是一种以空间换时间的做法。
#program pack(4)//设置默认对齐数是4
6.sizeof求空结构体大小
Linux:sizeof(struct)//0;
Windows://报错,1个结构体/联合中至少有一个变量
所以结构体定义时,不能为空
7.结构体传参:
数组名作为形参传参时会发生降级
但是如果结构体内含有数组,以结构体变量作为形参传参时,结构体内数组不会发生降级,会直接将整个数组直接拷贝形成一个临时变量(耗时,耗空间),所以在使用结构体传参时,要传结构体的地址
二、位段
位端的声明与结构体类似,有俩个不同
- 位段的成员必须是int ,unsigned int 或 signed int或char(char也属于整形家族)。
- 位段的成员名后边有一个冒号和一个数字
struct A
{
int _a:2;
int_b:5;
int _c:10;
int _d:30;
};
位段的内存分配:
- 位段的成员都是整形家族
- 位段的空间是按照需要以4字节(int)或者1个字节(char)的方式来开辟的
- 位段涉及很多不确定因素,位段是不跨平台的,注重可一直的程序应该避免使用文段
位段跟结构体相比,位段可以达到相同的效果,但是可以很好的节省空间,但是有跨平台的问题存在
三、枚举
枚举顾名思义就是一一列举
{}中的内容是枚举类型的可能取值,这些值默认从0开始,依次递增,当然在定义的时候也可以赋初值
枚举的优点:
- 增加代码的可读性和可维护性
- 和#define定义的标识符比较枚举有类型检查,更加严谨
- 防止了命名污染(封装)
- 便于调试
- 使用方便,一次可以定义多个常量
四、联合
联合也是一种特殊的自定义类型,特征是这些成员共用一块空间(所以联合也叫共用体)
union Un
{
char c;
int i;
};
printf("%d\n",sizeof(un));//输出4
联合的特点:
- 联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成原的大小(因为他要有能力保存最大的那个成员)
- 对联合的每个成员取地址,是同一个地址
联合的大小:
- 联合的大小至少是最大成员的大小
- 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍