代码示例: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 + 显式字节序转换。