结构体
定义
使用结构体时,用户可以自定义数据类型,在一个结构体的定义中,可以在自定义数据类型中定义一个或多个已定义的数据类型。例如int、long long、double、或其他自定义的数据类型等等。一个基本的结构体的定义例如:
struct S{
int a;
char ch;
double f;
// 包含的变量
void read(){
cin>>a>>ch>>f;
}
// 也可以在结构体中包含函数
};// 注意不要忘记了这里的分号
S s[100]; // 定义S类型数组
__ 结构体的核心特性: __
-
数据聚合:将逻辑相关的多个数据项组合在一起
-
成员多样性:可以包含任意类型的成员(基本类型、数组、指针、其他结构体等)
-
默认公开性:成员默认是public访问权限(与class的private默认不同)
-
内存连续性:成员在内存中按声明顺序连续排列(可能有填充字节)
高级用法
位域(Bit Fields):
允许指定成员占用的位数,常用于硬件编程和协议设计:
struct StatusRegister {
unsigned int error : 1; // 1位
unsigned int ready : 1; // 1位
unsigned int mode : 2; // 2位
unsigned int : 4; // 未使用的4位
unsigned int value : 8; // 8位值
};
柔性数组(Flexible Array Member):
C99引入的特性,允许结构体包含大小不确定的数组(必须是最后一个成员):
struct DynamicString {
int length;
char data[]; // 柔性数组成员
};
联合体
定义
联合体是一种特殊的数据类型,允许在同一内存位置存储不同的数据类型。所有成员共享同一块内存空间,其大小由最大成员决定。
关键特性:
- 内存共享:所有成员占用同一内存区域
- 瞬时单一性:任何时候只能有一个成员包含有效值
- 大小决定:联合体大小等于其最大成员的大小(考虑对齐)
- 类型转换:可视为隐式的类型转换机制
联合体的典型应用场景
类型转换:
union Converter {
float f;
unsigned int i;
char bytes[4];
};
Converter c;
c.f = 3.14f;
// 现在可以通过c.i或c.bytes访问float的二进制表示
变体记录(Variant Records):
表示可能具有多种形式的数据:
union Variant {
int intVal;
double doubleVal;
char* stringVal;
};
协议解析:
解析网络协议或文件格式时,同一内存区域可能包含不同类型的数据:
union IPAddress {
uint32_t address;
uint8_t octets[4];
};
联合体的限制与风险
主要限制:
- 不能包含引用类型的成员
- 不能继承或被继承
- C++11前不能包含有非平凡构造函数的成员(如std::string)
使用风险:
- 类型混淆:错误访问非当前活跃成员导致未定义行为
- 构造/析构问题:需要手动管理复杂类型的生命周期
- 可移植性问题:字节序(Endianness)问题影响跨平台使用
结构体与联合体的对比分析
特性 | 结构体(struct) | 联合体(union) |
---|---|---|
内存使用 | 各成员有独立存储空间 | 所有成员共享存储空间 |
存储大小 | 所有成员大小之和(含填充) | 最大成员的大小 |
成员访问 | 可同时访问所有成员 | 同一时间只能访问一个成员 |
默认访问控制 | public | public |
构造函数 | 支持 | C++11起支持 |
继承 | 支持 | 不支持 |
典型用途 | 数据聚合 | 类型转换、变体记录 |
结构体和联合体作为C++的基础复合数据类型,在很多领域仍有不可替代的价值。理解它们的底层机制和适用场景,能够帮助开发者编写出更高效、更贴近硬件的代码。在现代C++开发中,虽然一些新特性(如std::variant)提供了更安全的替代方案,但在需要精细控制内存布局或与C代码交互的场景中,传统结构体和联合体仍然是重要工具。