文章目录
- 一、结构体的使用
- 1. 结构体声明
- 2. 变量创建与初始化
- 3. 特殊声明与陷阱
- 二、内存对齐
- 1. 规则:
- 2. 示例分析:
- 3. 修改默认对齐数:
- 三、结构体传参
- 四、结构体实现位段
- 1. 定义
- 2. 内存分配
- 3. 应用场景
- 4. 跨平台问题:
- 5. 注意事项:
- 关键总结
一、结构体的使用
1. 结构体声明
struct Stu { // struct 关键字 + 标签(tag)char name[20]; // 成员变量int age; // 成员类型可不同char sex[5];char id[20];
}; // 分号不可省略
2. 变量创建与初始化
// 顺序初始化
struct Stu s1 = {"张三", 20, "男", "20230818001"};// 指定成员初始化(C99+)
struct Stu s2 = {.age=18, .name="lisi", .id="20230818002", .sex="女"};
3. 特殊声明与陷阱
· 匿名结构体(只能使用一次):
struct { int a; char b; } x; // 无标签
struct { int a; char b; } *p;
p = &x; // 错误!编译器认为两者类型不同
· 自引用正确方式:
struct Node { // 错误:struct Node next;(无限递归)int data;struct Node* next; // 正确:使用指针
};
· typedef 陷阱:
typedef struct { // 错误:内部提前使用Nodeint data;Node* next; // ❌ 未定义
} Node;// 正确写法
typedef struct Node {int data;struct Node* next;
} Node;
二、内存对齐
1. 规则:
· 首成员偏移量 = 0
· 其他成员对齐数 = min(编译器默认对齐数, 成员大小)
· VS默认对齐数 = 8,Linux gcc无默认值(对齐数=成员大小)
· 结构体总大小 = 最大对齐数的整数倍
· 嵌套结构体:嵌套的结构体成员对齐到自身内部最大对齐数的整数倍处,结构体的整体大小是所有元素中最大对齐数的整数倍
2. 示例分析:
struct S1 { char c1; int i; char c2; }; // 大小=12 (1+3填充+4+1+3填充)
struct S2 { char c1; char c2; int i; }; // 大小=8 (1+1+2填充+4)
节省空间技巧:将小成员集中放置(对比S1 vs S2)
3. 修改默认对齐数:
#pragma pack(1) // 对齐数设为1(无填充)
struct S { char c1; int i; char c2; }; // 大小=6
#pragma pack() // 恢复默认对齐数
三、结构体传参
· 传地址优于传结构体:
void print(struct S* ps) { // ✅ 推荐:传递指针(4/8字节)printf("%d\n", ps->num);
}
void print(struct S s) { // ❌ 避免:大结构体拷贝开销大printf("%d\n", s.num);
}
原因:传值导致拷贝开销,降低性能。
四、结构体实现位段
1. 定义
位:二进制位(比特位)
struct A { // 位段声明int _a:2; // 占2比特int _b:5; // 占5比特int _c:10; // 占10比特int _d:30; // 占30比特(不能超过自身大小,即<=32)
}; // 总大小:8字节(2个int)
· 成员主要为整形
2. 内存分配
· 空间按需以4字节(int)或1字节(char)开辟
· 给定空间后,成员在字节内的分配顺序由编译器决定(从左向右/从右向左)
· 当剩余空间不够存储一个成员时,剩余空间是浪费与否也取决于编译器
3. 应用场景
. 如_a中只需要存储0、1、2、3数字,则_a只需要两个比特位的空间,避免空间的浪费
· 网络协议头(如IP数据报):
| 4位版本号 | 4位首部长度 | 8位服务类型 | 16位总长度 | ...
用位段精简存储(如4位版本号仅需半字节)
4. 跨平台问题:
· int位段符号不确定(signed/unsigned)
· 最大位数依赖机器(16位机最大16,32位机最大32)
· 剩余位处理方式不确定(舍弃或利用)
5. 注意事项:
struct A sa;
scanf("%d", &sa._b); // ❌ 错误:位段成员无独立地址
// 正确做法:
int b;
scanf("%d", &b);
sa._b = b;
关键总结
主题 要点
结构体声明 分号不可省;避免匿名结构体自引用
内存对齐 掌握4条规则;通过成员排序节省空间;#pragma pack修改对齐数
传参方式 首选传地址(避免拷贝开销)
位段 节省空间但不可移植;成员无地址;慎用于跨平台程序
应用场景 协议封装、硬件寄存器映射等空间敏感场景
注:位段内存分配示例(假设小端存储):
struct S { char a:3; char b:4; char c:5; char d:4; };
struct S s = {0};
s.a = 10; // 二进制: 010 (存储低3位)
s.b = 12; // 二进制: 1100 (存储后续4位)
// 内存布局: | 1100 010 | ???? ??? | ... |