1
typedef struct {

/*has 15 pointers*/ // ==> 15 x 4 = 60 bytes ;

uint16_t;           // ==>           2 bytes

uint16_t array[];
} dummy_struct;

CASE-A)sizeof(dummy_struct)返回 64 字节

CASE-B) 如果我尝试打印,

((int) &(((dummy_struct *)(0))->array[0]))这将打印 62 个字节。

这也打印 62 个字节:((int) &(((dummy_struct *)(0))->array))

我不明白为什么会有价值变化?不应该也sizeof()返回 62 吗?

如果有这 2 个额外字节的填充,它不应该发生在结构中的灵活长度成员之前吗?如果是这样的话,CASE-B 不应该打印 64 而不是 62 吗?

编辑:

typedef struct {
    uint32_t temp;
    uint8_t array[][6];
} dummy2;
         printf("%d %d\n", sizeof(dummy2), offsetof(dummy2, array));  // PRINTS 4 4
         printf("%d \n",((int) &(((dummy2 *)(0))->array[0])));   // PRINTS 4

为什么前面的例子没有发生同样的效果?填充似乎没有在这里发生。那么,上一个示例的可能原因是在灵活尺寸成员之后发生了填充?

4

4 回答 4

4

sizeof返回整个结构的大小,而您的其他两个表达式返回成员的偏移量,array恰好是struct. 您可以使用 获得相同的结果offsetof,如下所示:

offsetof(dummy_struct, array) // This is 62

ideone 上的演示。

于 2013-05-08T17:30:28.733 回答
1

填充可能不会出现在虚拟数组之前,因为虚拟数组不需要它,因为类型是uint16_t,大概只需要 2 字节对齐,而不是 4。

也就是说,我敢打赌这是高度依赖于实现和目标的。

于 2013-05-08T17:20:09.407 回答
0

首先,这不是 VLA,它是一个灵活的数组成员。VLA 只能是自动变量(即堆栈上的常规变量),不能是结构的成员。这是因为编译器所做的很多事情都依赖于知道它操作的元素的大小。

根据您的评论,您似乎在一个 32 位平台上,该平台对指针有 4 字节对齐要求,对 16 位整数有 2 字节对齐要求。这就是为什么你得到一个 64 字节的 sizeof。出于 sizeof 的目的,就好像你的结构中没有灵活的数组成员,所以我们现在可以忽略它。灵活的数组成员是“假”成员,它不占用任何空间。

编译器在 uint16_t 之后添加 2 个字节的填充,以保证 dummy_struct 数组中的指针具有 32 位对齐。想象一个由 2 个虚拟结构组成的数组,如果没有填充,第一个指针将在 uint16_t 之后立即开始,并且不会在 32 位边界上对齐。

请注意,您通常可以强制编译器不填充,但没有可移植的方法来执行此操作。以 gcc 为例,您可以attribute ((packed))在结构上使用。如果你这样做, sizeof(dummy_struct) 将返回 62 个字节。

对于 B,您基本上是在打印灵活数组成员的偏移量。C99 标准说:

作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型;这称为灵活数组成员。在大多数情况下,灵活数组成员被忽略。特别是,结构的大小就像省略了柔性数组成员一样,只是它可能具有比省略所暗示的更多的尾随填充。然而,当一个 . (或->)运算符的左操作数是(指向)具有灵活数组成员的结构,右操作数命名该成员,它的行为就像该成员被替换为最长的数组(具有相同的元素类型) 不会使结构大于被访问的对象;数组的偏移量应保持灵活数组成员的偏移量,即使这与替换数组的偏移量不同。

因此,当您使用 -> 时,FAM 的行为就像它是一个常规数组,具有它可以拥有的最大大小,而不会更改 sizeof 报告的大小(64 字节)。在这种情况下,您只能适应单个 16 位整数而不更改大小。在这个虚构的结构中,没有填充,并且一个元素的虚构数组的偏移量为 62(就在 uint16_t 之后)。所以这就是你得到62的原因。

如果您的 FAM 是 int32_t,您可以在不更改大小的情况下容纳 0 个元素(您需要 2 个字节的填充来进行对齐)。标准说它的行为就像一个大小为 1 的数组。所以你的 FAM 将在偏移量 64 处,就像 sizeof 返回的那样。

让我重申一下:如果你简单地更改int16_t array[]int array[],A) 仍将返回 64,但 B) 现在将返回 64,而不是 62。

这也是您的第二个示例中发生的情况。您的 FAM 现在是一个指针数组。您在 32 位平台上,结构为 4。您可以在 FAM 中放置 0 个元素,而无需更改大小。所以它的偏移量是4。

于 2013-05-08T18:14:12.753 回答
0

在没有灵活数组成员的情况下,假设系统需要对 32 位整数进行 32 位对齐,则结构的大小将为 64 字节,包括末尾的两个字节填充。如果要添加一个包含偶数个 16 位值的固定大小的数组,则结构的大小会随着添加项的大小而增长。

虽然可以提出这样的论点,即使用具有灵活数组成员的结构的代码将知道它是否需要调整项目的计算大小以确保连续存储的项目具有正确的对齐方式,因此sizeof()应该报告该部分的大小在柔性构件之前的结构中,添加阵列会减小结构的报告大小,这将是“令人惊讶的”行为。可以说,该语言处理这种情况的正确方法是sizeof要求指定第二个参数,该参数给出数组中的项目数,在这种情况下sizeof(dummy_struct,1)会产生 64 但sizeof(dummy_struct,2)会产生 68。

于 2013-05-08T20:57:22.600 回答