编程系统程序员

解释 C 语言中嵌套结构和对齐 (struct alignment) 的工作机制。如何控制结构的大小,以及可能出现的问题?

用 Hintsage AI 助手通过面试

答案。

在 C 语言中,结构 (struct) 可以包含其他结构 和各种数据类型。然而,结构内部字段的位置可能会影响其 大小和对齐。编译器会添加额外的字节 (padding) 以遵循最大字段的对齐 (alignment)。这对于性能和处理器的正确工作是重要的。

如果结构包含嵌套结构,对齐会递归应用:

  • 结构的大小总是大于或等于最大字段的对齐。
  • 嵌套结构可能会导致意想不到的偏移,从而使 sizeof(struct) 大于字段大小的总和。

如何控制大小?

  1. 按照大小降序排列字段。
  2. 使用对齐指令(例如,MSVC 中的 #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 结构,但没有考虑到在没有对齐的平台上,单个字段无法正常工作(处理器不支持错位访问)。结果:在处理网络数据包时出现硬件异常。


历史

服务器处理一个由结构记录组成的外部文件。在更新编译器后,结构的大小发生了变化(对齐不同)。文件中的旧数据无法正确读取,部分信息变得 "损坏"。