C数组可以在元素之间包含填充吗?

我听说有传言说,在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的结尾和struct foo的结尾之间可能存在填充,并且标准声明foo的开头和foo.values的开头之间没有填充。 但是,是否有人引用引用标准,其中foo.values的元素之间没有填充?

不,在数组的元素之间永远不会有填充。 这是特别不允许的。 C99标准调用数组类型“数组类型描述了连续分配的非空对象集……”。 相反,结构是“顺序地”,而不是“连续地”分配。

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

小心点。 填充可以在结构的末尾添加,但不会在您在问题中声明的数组元素之间添加。 数组总是引用连续的内存,尽管结构数组可能会在每个元素作为结构本身的一部分添加填充。

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

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

不同类型可能具有不同的对齐要求。 某些类型需要在字边界上对齐,其他类型需要在双边或甚至四字边界上对齐。 为此,结构可以在其成员之间包含填充字节。 可能需要尾随填充字节,因为直接在结构上的内存位置也必须符合结构的对齐要求,即如果bar的类型为struct foo * ,则

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

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

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

是的,有点。 变量通常与某些边界对齐,具体取决于变量。 举例来说,例如:

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

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

对于某些类型T, sizeof(T) 可以或可以不等于 sizeof(Ta) + sizeof(Tb) + sizeof(Tc) ...等。

通常,这完全取决于编译器和体系结构。 在实践中,它永远不重要。

考虑:

 struct { short s; int i; } s; 

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

值得强调的是,这是不一定由C标准定义的实现行为。 非常类似于短裤,整数和多头(C标准只是说短裤不会比整数更大,多头也不会小于整数,最终可能会达到16/32 / 32,16 / 32/64 ,32/32/64或许多其他配置)。