跳到主要内容
🔍

代码示例: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. 交叉编译到板卡时,位段布局以目标编译器手册为准,不沿用主机实测值。
    #
    # 一句可背的结论:位段是"编译器替你打包"的便利工具,打包方式(位顺序等)是实现定义的;
    # 可移植代码要么自检布局,要么用移位+掩码显式表达。