在 C 语言中,结构 (struct) 可以包含其他结构 和各种数据类型。然而,结构内部字段的位置可能会影响其 大小和对齐。编译器会添加额外的字节 (padding) 以遵循最大字段的对齐 (alignment)。这对于性能和处理器的正确工作是重要的。
如果结构包含嵌套结构,对齐会递归应用:
#pragma pack 或 GCC/Clang 中的 __attribute__((packed)))。示例:
#include <stdio.h> struct Inner { char c; int x; }; struct Outer { char a; struct Inner b; short s; }; int main() { printf("sizeof(struct Inner) = %zu\n", sizeof(struct Inner)); printf("sizeof(struct Outer) = %zu\n", sizeof(struct Outer)); return 0; } // sizeof(struct Inner) = 8 (在 64 位上), sizeof(struct Outer) = 16 或 24
使用 pack 和 packed 通过忽略对齐来减小大小,但这可能会降低性能或在某些平台(如 ARM、DSP 等)上引发错误。
问题: 是否可以保证在所有平台上同一结构的大小相同?
答案: 不可以!C 标准不保证相同的对齐、字节顺序 (endian),并且可能在字段之间和结构末尾 "添加" padding。为了实现结构的二进制兼容性,使用手动对齐控制,并始终在每个目标平台上显式测试 sizeof。
示例:
struct Data { char c; int x; }; // sizeof(Data) 通常在 64 位上为 8,在 32 位上为 5 或 8
历史
在通过二进制协议在微控制器 (ARM) 和 PC 之间交换结构时,从 ARM 传来的数据与 PC 上的预期不符——由于不同的 padding 和字节顺序。导致解码的参数不正确,从而导致设备控制的物理错误。
历史
在网络协议中为了加快数据发送,添加了 packed 结构,但没有考虑到在没有对齐的平台上,单个字段无法正常工作(处理器不支持错位访问)。结果:在处理网络数据包时出现硬件异常。
历史
服务器处理一个由结构记录组成的外部文件。在更新编译器后,结构的大小发生了变化(对齐不同)。文件中的旧数据无法正确读取,部分信息变得 "损坏"。