文章目录
- 前言
- 1. 联合体
- 1.1 联合体类型的声明
- 1.2 联合体类型的特点
- 1.3 联合体大小的计算
- 1.4 用联合判断大小端
- 2. 枚举
- 2.1 枚举类型的声明
- 2.2 枚举类型的优点
- 2.3 枚举类型的使用
前言
在C语言中,除了基本数据类型(如int、char、float)和数组,程序员还可以通过结构体、联合体和枚举来自定义复杂的数据类型。这些自定义类型极大地增强了C语言描述现实世界数据的能力。
本文将重点介绍联合体和枚举这两种自定义类型。联合体以其独特的内存共享机制,在节省内存和灵活解释数据方面发挥着重要作用;而枚举则为程序中的整型常量提供了更具可读性和安全性的表示方式。理解并掌握它们,是迈向高级C语言编程的关键一步。
1. 联合体
联合体是C语言中一种特殊的数据类型,它允许在同一块内存空间中存储不同类型的数据成员。与结构体为每个成员分配独立内存不同,联合体的所有成员共享同一段内存。这意味着,在任意时刻,联合体中只有一个成员是有效的,对其中一个成员的赋值会覆盖其他成员的值。
1.1 联合体类型的声明
声明一个联合体类型使用关键字union,其语法与结构体(struct)非常相似:
union联合体标签{成员类型1成员名1;成员类型2成员名2;// ... 更多成员};union:声明联合体类型的关键字。- 联合体标签:联合体类型的名称,遵循C语言标识符命名规则。
- 成员列表:用花括号
{}包裹,内部定义了联合体的各个成员,每个成员都有自己的类型和名称。
示例:声明一个简单的联合体:
#include<stdio.h>// 联合类型的声明unionUn{charc;inti;};intmain(){// 联合变量的定义unionUn un={0};// 计算联合变量的大小printf("%d\n",sizeof(un));//输出4return0;}1.2 联合体类型的特点
联合体最核心的特点在于其内存共享机制,这带来了以下几个关键特性:
所有成员共享同一内存地址
联合体的所有成员都从同一内存地址开始存储。这意味着,通过不同的成员名访问的是同一块内存区域。同一时间只有一个成员有效
由于内存共享,当你给一个成员赋值后,再访问其他成员将得到未定义的值(可能是之前值的残留,也可能是被覆盖后的新值)。程序员需要自己记录当前哪个成员是“活跃”的。大小由最大成员决定
联合体变量占用的内存大小,等于其所有成员中所需空间最大的那个成员的大小。编译器会确保联合体的大小至少能容纳下最大的成员,并可能进行内存对齐。
1.3 联合体大小的计算
计算联合体的大小需要遵循两个原则:
- 大小至少等于其最大成员的大小。
- 大小必须是所有成员类型对齐要求的整数倍(内存对齐原则)。
计算步骤:
- 找出所有成员中,占用空间最大的成员的大小(
sizeof(最大成员))。 - 找出所有成员中,对齐要求最严格的成员的对齐值(通常等于其大小)。
- 最终联合体的大小是最大成员大小向上取整到最严格对齐值的整数倍。
unionExample{charc;// 大小1字节,对齐要求1字节inti;// 大小4字节,对齐要求4字节(在常见32/64位系统上)doubled;// 大小8字节,对齐要求8字节};- 最大成员是
double d,大小为8字节。 - 最严格的对齐要求也是
double的8字节。 - 因此,
union Example的大小为8字节。
可以使用sizeof运算符验证:
printf("Size of union Example: %zu bytes\n",sizeof(unionExample));// 输出 8与结构体大小对比:
structSExample{charc;inti;doubled;};// 在考虑对齐(如按8字节对齐)后,此结构体大小可能为 1+(3填充)+4+(4填充)+8 = 24字节。可以看到,联合体通过共享内存,在存储“互斥”数据时,能比结构体节省大量空间。
1.4 用联合判断大小端
我们可以写一个程序,判断当前机器是大端还是小端。
int check_sys() { union { int i; char c; }un; un.i = 1; return un.c;//返回1是小端,返回0是大端 }2. 枚举
枚举是C语言中一种用于定义一组命名整型常量的自定义数据类型。
2.1 枚举类型的声明
声明一个枚举类型使用关键字enum,其基本语法如下:
enum枚举标签{枚举常量1,枚举常量2,// ... 更多常量};enum:声明枚举类型的关键字。- 枚举标签:枚举类型的名称,遵循C语言标识符命名规则。
- 枚举常量列表:用花括号
{}包裹,内部列出所有枚举常量,常量之间用逗号分隔。
示例:声明一个表示星期的枚举类型:
enumWeekday{MONDAY,// 默认值为 0TUESDAY,// 默认值为 1WEDNESDAY,// 默认值为 2THURSDAY,// 默认值为 3FRIDAY,// 默认值为 4SATURDAY,// 默认值为 5SUNDAY// 默认值为 6};枚举常量的值:
- 默认情况下,第一个枚举常量的值为0,后续常量依次递增1。
- 可以显式地为枚举常量指定整数值,未指定的常量将基于前一个值递增1。
enum Color { RED = 1, GREEN, // 值为 2 BLUE = 5, YELLOW // 值为 6 };
2.2 枚举类型的优点
我们可以使用#define定义常量,为什么非要使用枚举?相比#define,枚举具有以下显著优点:
增加代码的可读性和可维护性,枚举常量使用有意义的名称,使代码意图一目了然。同时,枚举常量集中定义在一处,便于统一管理和修改。
和
#define定义的标识符比较,枚举有类型检查,更加严谨便于调试,预处理阶段会删除
#define定义的符号使用方便,一次可以定义多个常量
枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用。
2.3 枚举类型的使用
enumColor//颜色{RED=1,GREEN=2,BLUE=4};enumColorclr=GREEN;//使用枚举常量给枚举变量赋值在C语言中,可以直接用整数给枚举变量赋值,但是在C++是不行的,C++的类型检查比较严格。