跳到主要内容
🔍

代码示例:1.3.7 共用体与大小端实战

全部示例均标注编译命令、适用环境与实测状态;完整验证记录见《03.5-代码编译运行验证记录》。

  • examples/ex1-union-endian.c · union 共享内存演示 + 大小端判断(本机自检)

    /* ex1-union-endian.c —— union 共享内存 + 大小端判断(1.3.7)
     * 适用环境:Linux / Windows(MinGW) 标准:C11
     * 编译:gcc ex1-union-endian.c -o ex1 -std=c11 -Wall -Wextra -Wpedantic
     * 运行:./ex1(Windows: ex1.exe)
     * 说明:写 u 后读 b 属"读非最后写入成员"(实现定义);本程序用于本机字节序自检。
     *       本输出为 x86_64 MinGW gcc 15.2.0 实测(小端)。
     */
    #include <stdio.h>
     
    union Word {
        unsigned int  u;
        unsigned char b[4];
    };
     
    int main(void)
    {
        union Word w;
     
        printf("sizeof(union Word)=%zu sizeof(unsigned int)=%zu(union 大小=最大成员)\n",
               sizeof(union Word), sizeof(unsigned int));
     
        w.u = 0x11223344u;
        printf("u = 0x%08X\n", w.u);
        printf("b[0]=0x%02X b[1]=0x%02X b[2]=0x%02X b[3]=0x%02X\n",
               w.b[0], w.b[1], w.b[2], w.b[3]);
     
        if (w.b[0] == 0x44) {
            printf("本机为小端序(低地址存低位字节)\n");
        } else {
            printf("本机为大端序(低地址存高位字节)\n");
        }
        return 0;
    }
     
  • examples/ex2-memcpy-convert.c · int 与 4 字节数组互转(memcpy 安全版)

    /* ex2-memcpy-convert.c —— int 与字节数组的安全互转(memcpy 版)(1.3.7)
     * 适用环境:Linux / Windows(MinGW) 标准:C11
     * 编译:gcc ex2-memcpy-convert.c -o ex2 -std=c11 -Wall -Wextra -Wpedantic
     * 运行:./ex2(Windows: ex2.exe)
     * 说明:memcpy 逐字节复制是标准保证的安全互转(替代 union 类型双关)。
     *       字节序列为本机字节序;跨机器传输前需网络字节序转换(6.1.2)。
     */
    #include <stdio.h>
    #include <string.h>
     
    static void to_bytes(unsigned int v, unsigned char out[4])
    {
        memcpy(out, &v, sizeof(v));
    }
     
    static unsigned int from_bytes(const unsigned char in[4])
    {
        unsigned int v;
        memcpy(&v, in, sizeof(v));
        return v;
    }
     
    int main(void)
    {
        unsigned int v = 0x01020304u;
        unsigned char bytes[4];
        unsigned int back;
     
        to_bytes(v, bytes);
        back = from_bytes(bytes);
     
        printf("v=0x%08X\n", v);
        printf("bytes[0..3]=%02X %02X %02X %02X(本机字节序的字节序列)\n",
               bytes[0], bytes[1], bytes[2], bytes[3]);
        printf("back=0x%08X(往返一致: %s\n", back, back == v ? "yes" : "no");
        return 0;
    }
     
  • examples/ex3-union-punning-portability.txt · union 类型双关的可移植性边界(conceptual:静态讲解,不编译不运行)

    # 1.3.7 union 类型双关的可移植性边界(conceptual 讲解文本,不编译不运行)
    #
    # union 读写"非最后写入"的成员 = 类型双关(type punning)
    # C11 6.5.2.3 注 95:任一时刻 union 对象中至多一个成员有值;读取非最后写入的成员
    # 会把该成员对应字节按新类型重新解释(reinterpret)——C 标准将其归为"实现定义"行为,
    # 部分历史资料(C89 时代)曾按未定义行为警告。工程现实:字节序判断、float 位模式查看
    # 等场景大量使用,但严格可移植代码应意识到这不是语言保证。
    #
    # 为什么不"保证"?
    # 1. 大小端差异:同一段字节在不同平台重解释出不同数值;
    # 2. 填充字节:union 成员含 struct 时可能存在实现定义的填充字节;
    # 3. 严格别名规则(6.5 p6/p7):通过不兼容类型的左值访问对象违反别名规则(union 成员
    #    访问是标准明确允许的例外之一,但直接类型转换指针仍然违规)。
    #
    # 安全替代(本章 ex2):
    # memcpy 逐字节复制是标准保证的做法,现代编译器会把它优化回等价的高效代码——
    # 用 memcpy 而不是 *(unsigned int*)&float 或 union 双关,既标准又无损性能。
    #
    # 一句可背的结论:union 双关是"工程上常见、严格意义上实现定义"的技巧;
    # 自检本平台字节序可以用它,跨平台传输与严格可移植代码请用 memcpy + 显式字节序转换。