
文章目录前言本文旨在系统性地介绍C语言中的联合体和枚举。一、联合体1.1、联合体类型声明1.2、联合体的特点1.3、联合体使用举例1.4、用联合体判断大小端二、枚举2.1、枚举类型声明2.2、枚举类型优点2.3、枚举类型的使用前言本文旨在系统性地介绍C语言中的联合体和枚举。一、联合体联合体union所有成员共享同一块内存大小至少为最大成员的大小。给一个成员赋值会修改其他成员的值因为共享内存所以联合体也叫“共用体”。1.1、联合体类型声明联合体union的类型声明语法与结构体非常相似使用 union 关键字。基本语法union名字{成员列表;};1.2、联合体的特点①所有成员共用同一块内存空间地址相同②联合体大小 ≥ 最大成员大小联合体至少能容纳最大的成员联合体大小必须是最大对齐数的整数倍③同一时刻只能安全使用一个成员修改一个成员会影响其他成员地址验证代码示例#includestdio.hunionUn{charc;inti;};intmain(){unionUn un{0};printf(%p\n,un);// 联合体起始地址printf(%p\n,un.i);// int 成员地址printf(%p\n,un.c);// char 成员地址// 三个地址完全相同return0;}联合体大小验证代码示例#includestdio.hunionUn1{charc[5];// 大小 5对齐数 1inti;// 大小 4对齐数 4};// 最大成员c[5]5 字节// 最大对齐数max(1, 4) 4// 大小5 不是 4 的倍数 → 对齐到 8// sizeof(union Un1) 8unionUn2{shortc[7];// 大小 147×2对齐数 2inti;// 大小 4对齐数 4};// 最大成员c[7]14 字节// 最大对齐数max(2, 4) 4// 大小14 不是 4 的倍数 → 对齐到 16// sizeof(union Un2) 16intmain(){printf(%d\n,sizeof(unionUn1));// 8printf(%d\n,sizeof(unionUn2));// 16return0;}内存修改验证代码示例#includestdio.hunionUn{charc;inti;};intmain(){unionUn un{0};un.i0x11223344;// 设置 int 值un.c0x55;// 修改 char修改低地址字节printf(%x\n,un.i);// 0x11223355低地址字节被修改return0;}1.3、联合体使用举例设计一个礼品兑换单包含三种商品商品公共属性特殊属性图书库存量、价格、商品类型书名、作者、页数杯子库存量、价格、商品类型设计衬衫库存量、价格、商品类型设计、可选颜色、可选尺寸将特殊属性放入联合体共享内存代码示例structgift_list{// 公共属性所有商品共有intstock_number;// 库存量doubleprice;// 定价intitem_type;// 商品类型1图书2杯子3衬衫// 特殊属性联合体同一时刻只使用一种union{struct{chartitle[20];// 书名charauthor[20];// 作者intnum_pages;// 页数}book;struct{chardesign[30];// 设计}mug;struct{chardesign[30];// 设计intcolors;// 可选颜色intsizes;// 可选尺寸}shirt;}item;};1.4、用联合体判断大小端代码示例#includestdio.hintcheck_sys(){union{inti;charc;}un;un.i1;// 内存中小端 → 01 00 00 00大端 → 00 00 00 01returnun.c;// 读取低地址字节}intmain(){intretcheck_sys();if(ret1){printf(小端\n);}else{printf(大端\n);}return0;}二、枚举枚举enum就是给整型常量起有意义的名字让代码自解释提高可读性和可维护性。枚举适用于取值范围有限且可以一一列举的数据。枚举常量是枚举类型中定义的具体值它们是整型常量在编译时确定不占用运行时内存。可用于任何需要整型常量的地方数组大小、case 标签、数组索引等。2.1、枚举类型声明枚举类型的声明使用 enum 关键字包含类型名和枚举常量列表枚举类型的可能取值。基本语法enum类型名{枚举常量1,枚举常量2,枚举常量3};枚举常量默认从 0 开始递增可以完全自定义值也可以部分自定义未指定的自动 1。代码示例// 基本枚举声明星期enumDay{Mon,// 0Tues,// 1Wed,// 2Thur,// 3Fri,// 4Sat,// 5Sun// 6};// 完全自定义枚举值enumColor1{RED_C12,GREEN_C14,BLUE_C18};// 部分自定义未指定的自动递增enumColor2{RED_C21,// 1GREEN_C2,// 2自动 1BLUE_C25,// 5BLACK_C2// 6自动 1};2.2、枚举类型优点①类型安全枚举变量有类型信息编译器能检测到类型不匹配的错误②调试友好调试器能显示枚举名称如 MON而不是数字如 0③批量定义enum { MON, TUE, WED }; 一行搞定三个常量④作用域控制枚举在函数内声明外部无法访问2.3、枚举类型的使用无限循环切换交通灯代码示例#includestdio.h#includewindows.h// Sleep() 函数Windows 平台专用// LIGHT_COUNT 自动等于前面常量的数量RED0, GREEN1, YELLOW2, LIGHT_COUNT3typedefenum{RED,// 0 - 红灯GREEN,// 1 - 绿灯YELLOW,// 2 - 黄灯LIGHT_COUNT// 3 - 自动统计状态总数用于循环}TrafficLight;intmain(){// 定义每个灯的名称用枚举值作数组索引// 指定初始化器C99[RED] 红灯 表示在索引 RED(0) 处存放该字符串constchar*message[]{[RED] 红灯,[GREEN] 绿灯,[YELLOW] 黄灯};// 定义每个灯的持续时间秒// 同样用枚举值作索引与 message 数组一一对应constintseconds[]{[RED]10,// 红灯持续 10 秒[GREEN]10,// 绿灯持续 10 秒[YELLOW]3// 黄灯持续 3 秒};// 初始化当前状态为红灯TrafficLight currentRED;printf( 自动红绿灯 (CtrlC 退出)\n\n);// 主循环无限循环切换交通灯while(1){// 用枚举值索引数组获取当前灯的名称和持续时间intsecseconds[current];printf(现在是 %s持续 %d 秒\n,message[current],sec);// 倒计时显示剩余秒数for(intisec;i0;i--){printf( 剩余 %2d 秒\n,i);Sleep(1000);// 暂停 1000 毫秒 1 秒}// 当前灯结束输出分隔线printf( %s 结束 \n\n,message[current]);// 切换到下一个灯// (current 1) % LIGHT_COUNT 实现循环// RED(0) → GREEN(1)// GREEN(1) → YELLOW(2)// YELLOW(2) → RED(0) 因为 3 % 3 0// current(current1)%LIGHT_COUNT;}return0;}