31

我听说在 C 语言中,包含在结构中的数组可能在数组元素之间添加了填充。现在很明显,任何一对元素之间的填充量不能改变,或者使用简单的指针算法计算数组中的下一个元素是不可能的。

该谣言还指出,未包含在结构中的数组保证不包含填充。我知道至少那部分是真的。

因此,在代码中,谣言是:

{
    // Given this:
    struct { int values[20]; } foo;
    int values[20];

    // This may be true:
    sizeof(values) != sizeof(foo.values);
}

我很确定那sizeof(values)将永远相等sizeof(foo.values)。但是,我无法在 C 标准(特别是 C99)中找到任何明确确认或否认这一点的内容。

有谁知道这个谣言是否在任何 C 标准中得到解决?

编辑foo.values:我知道在数组的结尾和结构的结尾之间可能有填充,并且标准规定在开头和开头foo之间不会有填充。但是,是否有人引用引用了标准,其中说 的元素之间没有填充?foofoo.valuesfoo.values

4

5 回答 5

38

不,数组元素之间永远不会有填充。这是明确不允许的。C99 标准将数组类型称为“数组类型描述了一组连续分配的非空对象......”。相比之下,结构是“顺序”分配的,而不是“连续”分配的。

结构中的数组之前或之后可能有填充;那完全是另一种动物。编译器可能会这样做以帮助对齐结构,但 C 标准并没有说明这一点。

于 2009-07-01T00:03:55.457 回答
11

在这里小心。可以在结构的末尾添加填充,但不会像您在问题中所说的那样在数组的元素之间添加填充。数组将始终引用连续的内存,尽管结构数组可能会将填充添加到每个元素作为结构本身的一部分。

在您的示例中,valuesandfoo.values数组将具有相同的大小。任何填充都将成为结构的一部分foo

于 2009-07-01T00:05:07.107 回答
3

下面解释了为什么结构可能需要在其成员之间甚至在其最后一个成员之后进行填充,以及为什么数组不需要:

不同的类型可能有不同的对齐要求。一些类型需要在字边界上对齐,其他类型需要在双字甚至四字边界上对齐。为了实现这一点,一个结构可能在其成员之间包含填充字节。可能需要尾随填充字节,因为直接位于结构之外的内存位置也必须符合结构的对齐要求,即如果bar是 type struct foo *,则

(struct foo *)((char *)bar + sizeof(struct foo))

产生一个有效的指针struct foo(即不会因为未对齐而失败)。

由于数组的每个“成员”都具有相同的对齐要求,因此没有理由引入填充。这也适用于结构中包含的数组:如果数组的第一个元素正确对齐,那么所有后续元素也是如此。

于 2009-07-01T00:42:13.693 回答
0

是的,有点。变量通常与某个边界对齐,具体取决于变量。以以下为例:

typedef struct
{
    double d;
    char c;
} a_type_t;

在我的系统上,double 和 char 分别是 8 个字节和 1 个字节。总共 9 个。但是,该结构将是 16 个字节,因此双精度数始终是 8 字节对齐的。如果我刚刚使用整数、字符等,那么对齐可能是 1、2、4 或 8。

对于某些类型 T,sizeof(T) 可能等于也可能不等于 sizeof(T.a) + sizeof(T.b) + sizeof(T.c) ...等。

通常,这完全取决于编译器和架构。在实践中,这并不重要。

于 2009-07-01T00:03:40.510 回答
-1

考虑:

struct {
  short s;
  int i;
} s;

假设短裤是 16 位,而您是 32 位,则大小可能是 8 字节,因为每个结构成员倾向于对齐一个字(在这种情况下为 32 位)边界。我说“可能”是因为它是特定于实现的行为,可以通过编译器标志等来改变。

值得强调的是,这是 C 标准不一定定义的实现行为。很像 shorts、ints 和 longs 的大小(C 标准简单地说 shorts 不会大于 int 并且 longs 不会小于 int,最终可能为 16/32/32、16/32/64 , 32/32/64 或许多其他配置)。

于 2009-06-30T23:57:04.893 回答