新号别搞:结构体+联合体+枚举 1、 联合体 (Union)使用union关键字。编译器只为最大的成员分配足够的内存空间。所有成员共用同一块内存空间它们的起始地址是相同的。特性给其中一个成员赋值其他成员的值也会跟着变化。1.1 大小计算规则联合的大小至少是最大成员的大小。对齐规则当最大成员大小不是最大对齐数的整数倍时要对齐到最大对齐数的整数倍。1.2 大小端判断int check() { int i 1; // 在内存中存储为 00 00 00 01 if (*(char*)i 1) // 取低地址的一个字节 return 1; // 小端 else return 0; // 大端 }小端模式低位字节存放在低地址。所以取出第一个字节就是 01大端模式高位字节存放在低地址。所以取出第一个字节就是 001.3相同成员的结构体和联合体对比2、枚举2.1 声明enum Color { RED, GREEN, BLUE };枚举顾名思义就是⼀⼀列举2.2 默认值从0开始依次递增 1即 RED0, GREEN1, BLUE2。当然也可以手动赋值。2.3 枚举的优点增加代码的可读性和可维护性和#define定义的标识符⽐较枚举有类型检查更加严谨。便于调试预处理阶段会删除 #define 定义的符号使⽤⽅便⼀次可以定义多个常量枚举常量遵循作⽤域规则枚举声明在函数内只能在函数内使⽤2.4 举例enum Color//颜⾊ { RED, GREEN, BLUE };{}中的内容是枚举类型的可能取值也叫 枚举常量 。取值都是有值的默认从0开始依次递增。3、结构体 (Struct)3.1 结构体类型的声明与初始化基本语法struct tag { member-list; } variable-list;3.1.1 结构体变量的创建和初始化struct Stu { char name[20];//名字 int age;//年龄 }; int main() { //按照结构体成员的顺序初始化 struct Stu s { 张三, 20, 男, 20230818001 }; printf(name: %s\n, s.name); printf(age : %d\n, s.age); }3.1.2 特殊声明匿名结构体省略标签名通常用于只定义一次的情况。自引用结构体内部包含指向同类型结构体的指针.3.1.3 定义结构体不要使⽤匿名结构体typedef struct Node { int data; struct Node* next; }Node;3.2 结构体内存对齐01. 结构体的第1个成员对⻬到和结构体变量起始位置偏移量为0的地址处02. 从第2个成员变量开始都要对齐到某个对齐数的整数倍的地址处03. 结构体总⼤⼩为最⼤对⻬数结构体中每个成员变量都有⼀个对⻬数所有对齐数中最大的的整数倍。04. 如果嵌套了结构体的情况嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍 处结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数的整数倍。3.2.1 对⻬数编译器默认的⼀个对⻬数 与 该成员变量⼤⼩的较⼩值。VS 中默认的值为 8 Linux中 gcc 没有默认对⻬数对⻬数就是成员⾃⾝的⼤⼩3.2.2 例子空间换时间 故而尽量让占用空间小的成员尽量集中在⼀起3.2.3修改默认对⻬数#pragma pack(1)//设置默认对⻬数为1#pragma pack() //取消设置的对⻬数还原为默认3.3 结构体传参参数要压栈会有时间和空间上的系统开销。结构体过大开销较大性能会降低故而传地址。struct S { int data[1000]; int num; }; struct S s { {1,2,3,4}, 1000 }; void print2(struct S* ps) { printf(%d\n, ps-num); } int main() { print2(s); //传地址 return 0; }3.4 结构体实现位段3.4.1 位段声明结构01. 位段的成员必须是 int、unsigned int 或signed int 在C99中位段成员的类型也可以选择其他整型家族类型。02. 位段的成员名后边有⼀个冒号和⼀个数字struct A { int _a : 2; int _b : 5; };3.4.2 位段的内存分配位段的成员可以是 int unsigned int signed int 或者是 char 等类型位段的空间上是按照需要以4个字节 int 或1个字节 char 的⽅式开辟的。位段涉及很多不确定因素位段不跨平台注重可移植的程序应避免使⽤位段。3.4.3 位段的跨平台问题int 位段被当成有符号数还是⽆符号数是不确定的。位段中最⼤位的数⽬不能确定位段中的成员在内存中从左向右分配还是从右向左分配标准尚未定义。当⼀个结构包含两个位段第⼆个位段成员⽐较⼤⽆法容纳于第⼀个位段剩余的位时是舍弃剩余的位还是利⽤这是不确定的。3.4.4 位段使用注意事项位段的⼏个成员共有同⼀个字节有成员的起始位置并不是某个字节的起始位置没有地址。内存中每个字节分配⼀个地址⼀个字节内部的bit位是没有地址的。不能对位段的成员使⽤操作符不能scanf直接给位段的成员输⼊值只能是先输⼊放在⼀个变量中然后赋值给位段的成员struct A { int _a : 2; int _b : 5; int _c : 10; int _d : 30; }; int main() { struct A sa {0}; scanf(%d, sa._b);//这是错误的 //正确的⽰范 int b 0; scanf(%d, b); sa._b b; return 0; }完