【C语言】深入理解C语言中的自定义数据类型:struct、union与enum
文章目录
- 前言
- 1. struct —— 结构体
- 1.1 结构体的定义与声明
- 1.2 声明结构体变量
- 1.3 结构体的内存布局
- 1.4 使用typedef简化结构体定义
- 2. union —— 共用体
- 2.1 定义与声明共用体
- 2.2 共用体的使用
- 2.3 共用体的内存布局
- 3. enum —— 枚举
- 3.1 定义与声明枚举
- 3.2 使用枚举
- 3.3 自定义枚举的值
- 3.4 枚举的内存大小
- 3.5 枚举的优缺点
- 4. struct、union 与 enum 的比较
前言
C语言中,结构体(struct
)、共用体(union
)和枚举(enum
)是三种常见的自定义数据类型,可以组织多个不同类型的变量为一个单一的复合类型,提高代码的可读性和组织性。
1. struct —— 结构体
结构体(struct
)是C语言中最常用的复合数据类型之一。它可以将多个不同类型的变量组织在一起,形成一个新的类型。结构体的变量可以包含不同的数据类型,这使得它非常适合描述一些复杂对象。
1.1 结构体的定义与声明
定义结构体时,我们使用struct
关键字,后面跟上结构体的名称,并定义其内部包含的成员。
struct Person {char name[50];int age;float height;
};
在上面的示例中,Person
是一个结构体类型,它包含三个成员:name
(字符串类型)、age
(整数类型)和height
(浮点数类型)。
1.2 声明结构体变量
定义完结构体类型后,我们可以在程序中声明变量并对其进行操作。
struct Person person1;
person1.age = 25;
person1.height = 5.9;
strcpy(person1.name, "John");
1.3 结构体的内存布局
结构体内存是按顺序分配的,但由于不同类型的变量可能具有不同的对齐要求,编译器通常会在成员之间插入填充字节,以确保每个成员的地址按照其对齐要求正确存放。内存布局的大小也受到这些填充字节的影响。
1.4 使用typedef简化结构体定义
在C语言中,结构体类型可以通过typedef
进行简化,避免在声明变量时重复写struct
关键字。
typedef struct {char name[50];int age;float height;
} Person;Person person2; // 不需要再写 struct
2. union —— 共用体
共用体(union
)与结构体非常相似,但它的每个成员共享同一段内存区域。这意味着,在任何时候,union
类型变量只有一个成员能够存储数据,而其他成员的数据会被覆盖。这使得union
在节省内存空间时非常有用,尤其是在存储不同类型数据时,只需要考虑当前使用的数据类型大小。
2.1 定义与声明共用体
union Data {int i;float f;char str[20];
};
在这个例子中,union Data
可以存储整数、浮点数或字符串,但它们共享同一内存区域,任何时候只能保存其中一个。
2.2 共用体的使用
union Data data1;
data1.i = 10;
printf("data1.i: %d\n", data1.i);data1.f = 220.5;
printf("data1.f: %f\n", data1.f);strcpy(data1.str, "Hello, World!");
printf("data1.str: %s\n", data1.str);
注意,在上述代码中,先存储的整数i
会被浮点数f
覆盖,浮点数f
又会被字符串str
覆盖。因此,共用体中的成员是互斥的。
2.3 共用体的内存布局
共用体的内存大小是其最大成员大小,也就是说,它的内存大小取决于最大成员的大小。例如,union Data
的内存大小为sizeof(char[20])
,即20个字节,因为str
是共用体中最大的一项。
3. enum —— 枚举
枚举(enum
)是一种为整型变量定义一组符号常量的方式。它允许我们为某些固定的值设置有意义的名称,使代码更加易读和维护。
3.1 定义与声明枚举
enum Weekday {Monday = 1,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
};
在这个例子中,enum Weekday
为一周的7天定义了符号常量。默认情况下,Monday
的值是1,接下来的天数自动递增。
3.2 使用枚举
enum Weekday today = Wednesday;
if (today == Wednesday) {printf("Today is Wednesday\n");
}
通过枚举,我们可以使用有意义的名字代替数字,使代码更具可读性。
3.3 自定义枚举的值
我们还可以自定义枚举值的起始值和增量。
enum Color {Red = 10,Green = 20,Blue = 30
};
此时,Red
的值为10,Green
为20,Blue
为30。
3.4 枚举的内存大小
枚举的底层实现是整数类型,通常为int
,因此它的内存大小通常为sizeof(int)
,但是在某些编译器中,可以通过typedef
或强制类型转换来改变枚举的底层类型。
3.5 枚举的优缺点
优点 | 缺点 |
---|---|
增强可读性:使用有意义的名字代替数字常量,使代码更易于理解。 | 内存消耗:枚举通常使用整数类型,可能会浪费内存。 |
类型安全:编译器会检查枚举值是否符合定义的类型范围。 | 缺少灵活性:枚举成员是静态的,不能动态添加或修改。 |
减少硬编码:通过为常量赋予名字,减少数字常量的硬编码。 | 与其他类型的兼容性差:枚举不能与其他类型(如 char 或 float )直接兼容。 |
自动赋值:枚举值会自动递增,简化赋值操作。 | 调试困难:调试时,枚举值通常显示为整数,难以识别具体含义。 |
提高代码可维护性:常量的名字增强了代码的自解释性,易于团队协作和后期维护。 | 无法直接进行运算:枚举值不能直接进行算术运算。 |
4. struct、union 与 enum 的比较
特性 | struct | union | enum |
---|---|---|---|
存储方式 | 每个成员都有独立内存空间 | 所有成员共享同一内存空间 | 每个枚举值都映射为一个整数值 |
内存大小 | 所有成员的内存大小之和 | 最大成员的内存大小 | 通常为整数类型的大小 |
使用场景 | 适用于描述包含不同类型的复合数据 | 适用于存储不同类型的数据,但每次只能存储一个值 | 适用于表示有限集合的常量值 |
成员类型 | 可以是任意类型 | 只能是简单类型(通常是基本数据类型) | 必须是整型常量 |
我们对三者进行简单总结:
struct
用于将不同类型的数据组织成一个集合,适合存储复合数据。union
允许多个成员共享同一块内存,可以节省空间,但每次只能保存一个成员的数据。enum
为一组常量值提供更具可读性的名称,用于表示有限集合的值。