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吗?
如果有两个额外字节的填充,不应该在结构中的弹性长度成员之前发生吗?如果是这种情况,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
为什么前一个例子没有发生同样的效果?填充似乎不会发生在这里。那么,上一个例子的可能原因是在弹性大小的成员之后发生填充?
答案 0 :(得分:4)
sizeof
返回整个结构的大小,而其他两个表达式返回array
成员的偏移量,恰好是struct
结束前的两个字节。您可以使用offsetof
获得相同的结果,如下所示:
offsetof(dummy_struct, array) // This is 62
答案 1 :(得分:1)
填充可能不会出现在虚拟数组之前,因为虚拟数组不需要它,因为类型为uint16_t
,大概只需要2字节对齐,而不是4。
那就是说,我敢打赌这是高度执行和目标依赖。
答案 2 :(得分:0)
首先,这不是VLA,它是一个灵活的阵列成员。 VLA只能是自动变量(即堆栈上的常规变量),而不是结构的成员。这是因为编译器确实依赖于知道它操作的元素的大小。
根据您的评论,您看起来像是在一个32位平台上,它对指针有4字节对齐要求,对16位整数有2字节对齐。这就是为什么你得到64字节的sizeof。对于sizeof,它就像你的struct中没有灵活的数组成员,所以我们现在可以忽略它。灵活的阵列成员是一个假的"会员,它不占用任何空间。
编译器在uint16_t之后添加2个字节的填充,以保证在dummy_struct数组中指针具有32位对齐。想象一个包含2个伪结构的数组,如果没有填充,第一个指针将在uint16_t之后开始,并且它不会在32位边界上对齐。
请注意,您通常可以强制编译器不要填充,但是没有可移植的方法来执行此操作。以gcc为例,您可以在结构上使用attribute ((packed))
。如果这样做,sizeof(dummy_struct)将返回62个字节。
对于B,您基本上打印柔性阵列成员的偏移量。 C99标准说:
作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型;这被称为灵活的阵列成员。在大多数情况下,将忽略灵活数组成员。特别地,结构的尺寸好像省略了柔性阵列构件,除了它可以具有比省略意味着更多的拖尾填充。但是,当一个。 (或 - >)运算符有一个左操作数,它是一个带有灵活数组成员的结构(指针),右操作数命名该成员,它的行为就好像该成员被最长的数组替换(具有相同的元素) type)不会使结构大于被访问的对象;数组的偏移量应保持为灵活数组成员的偏移量,即使这与替换数组的偏移量不同。如果此数组没有元素,则其行为就好像它有一个元素,但如果尝试访问该元素或生成一个超过它的指针,则行为是未定义的。
因此,当您使用 - >时,FAM就像它是一个常规数组,具有最大尺寸,而不会更改sizeof(64字节)报告的大小。在这种情况下,您只能在不更改大小的情况下拟合单个16位整数。在这个虚构的结构中,没有填充,一个元素的虚数组的偏移量将是62(在uint16_t之后)。这就是为什么你得到62。
如果你的FAM是int32_t,你可以在不改变大小的情况下拟合0元素(你需要2个字节的填充来进行对齐)。标准说这个行为就像一个大小为1的数组。所以你的FAM将在偏移64处,就像返回的大小一样。
让我重新迭代:如果您只是将int16_t array[]
更改为int array[]
,A)仍会返回64,但B)现在将返回64而不是62。
这也是你的第二个例子中发生的事情。你的FAM现在是一个指针数组。您使用的是32位平台,结构为4.您可以在FAM中放入0元素而不更改大小。所以它的偏移量是4。
答案 3 :(得分:0)
如果没有灵活的数组成员,假设系统需要32位对齐32位整数,则结构的大小为64字节,包括末尾的两个填充字节。如果要添加一个包含偶数个16位值的固定大小数组,则结构的大小将增加所添加项的大小。
虽然可以证明使用具有灵活数组成员的结构的代码将知道是否需要调整项的计算大小以确保连续存储的项具有正确的对齐,因此{{1}应该在柔性构件之前报告结构部分的大小,增加一个阵列减少报告的结构大小将是“令人惊讶的”行为。可以说,语言处理这种情况的正确方法是让sizeof()
要求指定第二个参数,给出数组中项目的数量,在这种情况下sizeof
将产生64但sizeof(dummy_struct,1)
1}}会产生68。