建网站_网站内容怎么做,烟台专业网站建设公司哪家好,人工智能公众号,安阳做网站电话自定义类型——结构体、枚举和联合 结构体结构体的声明匿名结构体结构体的自引用结构体的初始化结构体的内存对齐修改默认对齐数结构体传参 位段枚举联合 结构体
结构是一些值的集合#xff0c;这些值被称为成员变量#xff0c;结构的每个成员可以是不同类型的变量。 数组是… 自定义类型——结构体、枚举和联合 结构体结构体的声明匿名结构体结构体的自引用结构体的初始化结构体的内存对齐修改默认对齐数结构体传参 位段枚举联合 结构体
结构是一些值的集合这些值被称为成员变量结构的每个成员可以是不同类型的变量。 数组是一些值的结合类型是相同的 结构体的声明 struct tag{member_list;}variable_list;//全局变量这里通过前面的列表创建的变量是全局变量 typedef struct tag{member_list;}tag;//相当于struct tagtypedef可以将复杂的类型简化
匿名结构体 struct{member_list;}variavle_list;//必须存在
匿名结构体类型如果没有对结构体类型重命名只能使用一次
结构体的自引用
//结构体的自引用
struct stu
{int age;struct stu* next;
};typedef struct stu
{int age;struct stu* next;
}stu;结构体的初始化
//结构体的初始化#includestdio.h
struct student
{char name[10];unsigned int age;char sex[5];
};int main(void)
{//初始化struct student n1 { 张三,21,男};//打印printf(%s %u %s, n1.name, n1.age, n1.sex);return 0;
}运行截图
结构体的内存对齐
//结构体的内存对齐
#includestdio.h
struct eg1
{int i;char j;char k;
};struct eg2
{char x;int y;char z;
};int main(void)
{//打印eg1printf(%zd\n, sizeof(struct eg1));//8//打印eg2printf(%zd\n, sizeof(struct eg2));//12return 0;
}结构体对齐规则
1.结构体的第一个成员对齐到结构体在内存中存放位置的0偏移处 2.从第二个成员开始每个成员都要对齐到一个对齐数的整数倍处 对齐数 结构体成员自身大小和默认对齐数的较小值 在VS中默认对齐数为8 Linux gcc没有对齐数对齐数就是成员自身大小 3.结构总大小为最大对齐数的较小值 4.如果结构体中嵌套了结构体成员要将嵌套的成员对齐到自己的成员中最大对齐数的整数倍处 5.结构体的总大小必须是最大对齐数的整数倍这里的最大对齐数是包含嵌套结构体成员中的对齐数的所以对齐数中的最大值
结构体内存对齐的原因
1.平台原因 不是所有的硬件平台都能访问任意地址上的任意数据的某些硬件平台只能在地址处取某些特定类型的数据否则会抛出硬件异常
2.性能原因 数据结构尤其是栈应该尽可能的在自然边界上对齐原因在于为了访问来对齐的内存处理器需要作俩次内存访问而对齐的内存仅需要一次访问 总结 结构体的内存对齐是拿空间来换取时间的做法满足对齐节省空间让占用空间小的成员尽量集中在一起 修改默认对齐数 #pragma pack()可以设置默认对齐数 //修改默认对齐数
#includestdio.h
//修改默认对齐数为2
#pragma pack(2)struct eg1
{char s1;int s2;
};//恢复默认对齐数
#pragma pack()struct eg2
{char s1;int s2;
};int main(void)
{//打印eg1printf(%zd\n,sizeof(struct eg1));//6//打印eg2printf(%zd\n, sizeof(struct eg2));//8return 0;
}总结 结构在对齐方式不合适的时候可以自己更改默认对齐数 结构体传参
//结构体传参
#includestdio.hstruct eg
{int arr[100];char ch[20];
}s1 { {1,2,3,4,5} ,abcdef};
//结构体传参
void print1(struct eg s1)
{printf(%s\n,s1.ch);
}
//结构体地址传参
void print2(struct eg* ps)
{printf(%s\n,ps-ch);
}
int main(void)
{//结构体传参print1(s1);//结构体地址传参print2(s1);return 0;
}运行截图
总结结构体传参的时候要传结构体的地址 原因在于函数传参的时候参数是需要压栈会有时间和空间上的系统开销 如果传递一个结构体对象的时候结构体过大参数压栈的系统开销比较大所以导致性能下降
位段
位段的声明和结构体的声明基本相似但也存在俩点不同
1.位段的成员必须为int,unsigned int或者 signed int 2.位段的成员名后面有一个冒号和一个数字
//位段
#includestdio.h
struct eg
{int _a : 2;int _b : 5;int _c : 10;int _d : 20;
};int main(void)
{printf(%zd,sizeof(struct eg));return 0;
}运行截图
位段二进制位可以节省空间
位段的内存分配 1.位段的成员可以是intunsigned int,signed int或者是char (属于整数家族)类型 2.位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的 3.位段涉及很多不确定因素位段时不跨平台的注重可移植的程序应该避免使用位段
位段的跨平台问题 1.int位段被当成有符号数还是无符号数是不确定的 2.位段中最大位的数目不能确定16位机器最大1632位机器最大32写成27时可能在16位机器上出现问题 3.位段中的成员在内存中从左到右分配而且从右向左标准尚未定义 4.当一个结构包含俩个位段第二个位段成员比较大无法容纳于第一个位段剩余的位时是舍弃剩余的位还是利用这是不确定的 总结跟结构相比位段可以达到同样的效果但是可以很好的节省空间但是有跨平台的问题存在 枚举
枚举即一 一列举
//枚举
enum Day
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};enum Color
{Green,Blue,Red,Orange
};enum Day和enum color都是枚举类型{ }中的内容是枚举类型的可能取值也叫枚举常量。这些枚举常量都是存在取值的默认是从0开始一次低递加1
也可以在定义的时候赋值
enum Day
{Mon 1,Tues 2,Wed 3,Thur 4,Fri 5,Sat 6,Sun 7
};枚举的优点 1.增加代码的可读性和可维护性 2.和#define定义的标识符比较枚举由类型检查更加严谨 3.防止了命名污染封装 4.便于调试 5.使用方便一次可以定义多个变量 联合
联合同样也是一种自定义类型这种类型定义的变量也包含一系列的成员特征是这些成员公用同一块空间所以联合也叫共同体
//联合
union eg
{char i;int j;
};特点
联合的成员是共用同一块内存空间的这样一个联合变量的大小至少是最大成员的大小因为联合至少得有能力保存最大的那个成员
联合大小的计算
1.联合的大小至少是最大成员的大小 2.当最大成员大小不是最大对齐数的整数的时候就有对齐到最大对齐数的整数倍
//联合
#includestdio.h
union eg
{char i;int j;
};
int main(void)
{union eg s;printf(%p\n, s.i);printf(%p\n, s.j);return 0;
}