避免填充“unfull”结构

时间:2013-11-16 15:53:37

标签: c

我试图给this answer提供一个“逻辑”反例 - 表示根据结构大小对结构成员进行排序可以最小化填充,当我遇到似乎不合逻辑的时候。

想象一下以下结构:

struct A
{
    int32_t a;
    int16_t b;
};

sizeof此结构通常会填充为8个字节,以确保astruct A数组中对齐。

现在对其他结构进行成像:

struct B
{
    struct A a, b;
    int16_t c, d;
};

struct C
{
    struct A a;
    int16_t c;
    struct A b;
    int16_t d;
};

正如预期的那样struct B由于填充而具有大小为20。但是,我希望struct C的大小为16,因为可以避免填充 ,但ideone和gcc(有或没有优化)给出24字节的大小,显然在每个成员之后填充2个字节。

我的理由是struct A实际上只有6个字节,必要时应填充,例如struct A数组或struct B中的用法。但是,struct C填充struct A是不必要的ca可以放在d的填充位置和bc相同的位置{1}}。

为什么编译器不会通过将a置于sizeof(struct A)的填充位置来最小化填充?


P.S。我了解memset(array_of_A, 0, N * sizeof *array_of_A)必须返回8.否则array_of_A之类的内容将无法正常运行,因为N * sizeof *array_of_A将包含填充,而sizeof(struct C)会忽略该填充。

我能想到的唯一问题可能是问题在于,通过上述优化,sizeof将比其所有成员的{{1}} 更小。但是,我不能想到这样的事情可能成为问题的情况(即不基于未定义行为的用法)。

2 个答案:

答案 0 :(得分:3)

struct C someC;
struct A someA;
*(struct A*)&(someC.a) = someA; 

如果编译器支持您描述的填充,则上述分配可能会失败(错误地写入someC.c)。

已编辑:上面的示例依赖于分配结构时的编译器行为。正如我所知道的(刚检查过的)gcc副本,因为结构是一个平坦的内存区域,这不是成员方面的。

已编辑:已从“失败”更改为“可能失败”,因为如果要复制填充位,则未定义,请参阅ISO_IEC_9899_2011第6.2.6.1节第6项:

  

当值存储在结构或联合类型的对象中时,包括在成员中   object,对象表示的字节,对应于任何填充字节   未具体的值.51)

和脚注51)

  

51)因此,例如,结构分配不需要复制任何填充位。

答案 1 :(得分:2)

memcpy(&someC.a, &someA, sizeof(someC.a))会写someC.c

这就是我试图了解sizeof()的评论 与众不同。要使memcpy()工作,sizeof(someC.a)必须这样做 与sizeof(someA)不同,{{1}}似乎要求很多 麻烦,很难找到错误。