代码示例:1.3.6 结构体与位段
全部示例均标注编译命令、适用环境与实测状态;完整验证记录见《03.5-代码编译运行验证记录》。
examples/ex1-struct-basics.c · 结构体基础(聚合/指定初始化 + 数组与指针访问)
/* ex1-struct-basics.c —— 结构体基础:定义/初始化/数组/指针访问(1.3.6) * 适用环境:Linux / Windows(MinGW) 标准:C11 * 编译:gcc ex1-struct-basics.c -o ex1 -std=c11 -Wall -Wextra -Wpedantic * 运行:./ex1(Windows: ex1.exe) */ #include <stdio.h> struct Point { int x; int y; }; struct Student { char name[16]; int id; int score; }; int main(void) { struct Point p = { 3, 4 }; /* 聚合初始化 */ struct Point q = { .x = 10, .y = 20 }; /* C99 指定初始化 */ struct Student st = { "Alice", 1001, 95 }; struct Student *ps = &st; /* 指针访问用 -> */ struct Point arr[3] = { { 1, 1 }, { 2, 2 }, { 3, 3 } }; /* 结构体数组 */ printf("p=(%d,%d) q=(%d,%d)\n", p.x, p.y, q.x, q.y); printf("student: %s id=%d score=%d\n", ps->name, ps->id, ps->score); printf("arr[2]=(%d,%d) 数组总大小=%zu\n", arr[2].x, arr[2].y, sizeof(arr)); return 0; }examples/ex2-struct-align.c · 内存对齐实测(offsetof 与 pragma pack)
/* ex2-struct-align.c —— 内存对齐实测:offsetof 与 pragma pack(1.3.6) * 适用环境:Linux / Windows(MinGW) 标准:C11 * 编译:gcc ex2-struct-align.c -o ex2 -std=c11 -Wall -Wextra -Wpedantic * 运行:./ex2(Windows: ex2.exe) * 说明:本输出为 x86_64 MinGW gcc 15.2.0 本机实测;对齐规则是实现定义的,换平台数值不同。 */ #include <stdio.h> #include <stddef.h> struct Mixed { char c; int i; char d; }; #pragma pack(push, 1) struct Packed { char c; int i; char d; }; #pragma pack(pop) int main(void) { struct Mixed m; m.c = 'A'; m.i = 42; m.d = 'B'; printf("sizeof(char)=%zu sizeof(int)=%zu\n", sizeof(char), sizeof(int)); printf("sizeof(struct Mixed)=%zu(成员之和为 6,多出的是对齐填充)\n", sizeof(struct Mixed)); printf("offsetof(Mixed): c=%zu i=%zu d=%zu(i 对齐到 4 的倍数)\n", offsetof(struct Mixed, c), offsetof(struct Mixed, i), offsetof(struct Mixed, d)); printf("m = {%c, %d, %c}\n", m.c, m.i, m.d); printf("sizeof(struct Packed)=%zu(pack(1) 取消填充)\n", sizeof(struct Packed)); printf("offsetof(Packed): c=%zu i=%zu d=%zu\n", offsetof(struct Packed, c), offsetof(struct Packed, i), offsetof(struct Packed, d)); return 0; }examples/ex3-bitfield-reg.c · 位段定义 8 位控制寄存器(本机布局实测)
/* ex3-bitfield-reg.c —— 位段定义 8 位控制寄存器(1.3.6) * 适用环境:Linux / Windows(MinGW) 标准:C11 * 编译:gcc ex3-bitfield-reg.c -o ex3 -std=c11 -Wall -Wextra -Wpedantic * 运行:./ex3(Windows: ex3.exe) * 说明:位段布局(位顺序/跨单元)是实现定义的;本输出为 x86_64 MinGW gcc 15.2.0 实测。 */ #include <stdio.h> /* 8 位控制寄存器:位 0 使能、位 1-2 模式、位 3-6 分频、位 7 保留 */ struct CtrlReg { unsigned int enable : 1; unsigned int mode : 2; unsigned int prescale : 4; unsigned int reserved : 1; }; int main(void) { struct CtrlReg reg = { 0 }; reg.enable = 1; /* 0b1 */ reg.mode = 2; /* 0b10 */ reg.prescale = 5; /* 0b0101 */ /* reserved 保持 0 */ printf("sizeof(struct CtrlReg)=%zu(8 个位段合入 1 个 unsigned int)\n", sizeof(struct CtrlReg)); printf("enable=%u mode=%u prescale=%u reserved=%u\n", reg.enable, reg.mode, reg.prescale, reg.reserved); return 0; }examples/ex4-bitfield-portability.txt · 位段可移植性边界(conceptual:静态讲解,不编译不运行)
# 1.3.6 位段可移植性边界(conceptual 讲解文本,不编译不运行) # # 为什么"位段寄存器映射"不总是可移植? # 位段(bit-field)只保证三件事(C11 6.7.2.1): # 1. 类型只能是 _Bool、signed/unsigned int 或其他实现定义类型(通常不允许指针/浮点); # 2. 单个位段的宽度不超过其声明类型的宽度; # 3. 同一结构体内位段按声明顺序分配存储("从左到右或从右到左"是实现定义的)。 # 其余全部实现定义:位段的位顺序(低地址是高位还是低位)、是否允许跨存储单元边界、 # 相邻位段之间的填充、单段宽度上限(err-7.3-13:资料"最多 31 位"是某实现限制,不是语言规则)。 # # 工程上的正确姿势: # 1. 寄存器映射用 unsigned int 位段(避免符号位参与造成意外); # 2. 首次使用前用已知值"自检"本平台位顺序(写 1 读回验证),或直接用移位+掩码宏替代位段; # 3. 位段结构体不用于序列化/跨平台传输——布局是实现定义的; # 4. 交叉编译到板卡时,位段布局以目标编译器手册为准,不沿用主机实测值。 # # 一句可背的结论:位段是"编译器替你打包"的便利工具,打包方式(位顺序等)是实现定义的; # 可移植代码要么自检布局,要么用移位+掩码显式表达。