c - 为什么结构的大小应反射(reflect)其对齐方式?

标签 c size padding memory-alignment

根据 Wikipedia :

the last member is padded with the number of bytes required so that the total size of the structure should be a multiple of the largest alignment of any structure member

在我的理解中,它的意思是:

struct A {
  char *p;     // 8 bytes
  char c;      // 1 byte
};
struct B {
  struct A a;  // 16 bytes
  char d;      // 1 bytes
};

结构 A 的大小为 16 字节,结构 B 的大小为 24 字节。

通常的解释是,A 的数组应该在数组地址加上索引乘以 A 的大小处访问其元素。

但我不明白为什么会这样。为什么我们不能说 A 的大小为 9 而 B 的大小为 10(均采用 8 字节对齐),并在索引到一个数组时使用特殊的“数组存储”大小数组?

当然,我们仍会以与其对齐方式兼容的方式将这些类型存储在数组中(使用 16 个字节来存储每个 B 元素)。然后,我们将通过考虑它们的对齐来简单地计算元素地址,而不是单独考虑它们的大小(编译器可以静态地这样做)。

例如,我们可以在 B 的 1Kb 字节数组中存储 64 个对象,而不是仅仅 42 个。

最佳答案

在 C 的每个翻译单元中,sizeof(T) 是相同的,无论 T 的上下文如何。您的提案将为 sizeof(T) 引入至少两个值:一个用于 T 的数组,另一个用于 T 的单个对象。这基本上将上下文相关性引入了 sizeof 运算符。它与 C 处理指针、数组和对象地址的方式不兼容。

考虑以下几点:

void zero_A(struct A *a) { memset(a,0,sizeof(*a)); }

/* ... */
struct A single;
struct A several[3];
struct B b;

b.d = 3;
zero_A(&b.a);
zero_A(&single);
zero_A(several+1);

根据您的提议,zero_A 必须知道传递给它的指针是否指向数组上下文中的 struct A(其中 sizeof(*a) == 16) 或 struct A 在数组上下文之外(其中 sizeof(*a) == 9)。标准 C 不支持这个。如果编译器猜错了,或者信息丢失了(例如:在通过 volatile struct A * 的往返过程中),那么 zero_A(&single) 将调用未定义的行为(通过写入 single 的边界),zero_A(&b.a) 将覆盖 b.d 并调用未定义的行为。

将结构紧密打包到数组中是一种相对不常见的要求,向 sizeof 添加上下文相关性会给语言、它的库和 ABI 带来很多复杂性。有时您需要这样做,C 为您提供了所需的工具:memcpy 和 union 。

关于c - 为什么结构的大小应反射(reflect)其对齐方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32100031/

相关文章:

c - Windows 服务器应用程序的 fork/chroot 等效项

iphone - 如何找到调整 View 大小的位置/原因?

向右推 CSS 导航项

ruby - 在 Ruby 中填充数组的方法

html - CSS:span 和 li 的高度不匹配

c - 数组和指针 : segmentation fault

python - 使用 MinGW 时,Windows 上的 C 中的 recvfrom 函数会跳过 UDP 数据

c - asm x86 中变量声明的顺序?

Java:找出对象的内存大小?

计算给定字符串中有多少个由空格分隔的整数值