我试图给this answer提供一个“逻辑”反例 - 表示根据结构大小对结构成员进行排序可以最小化填充,当我遇到似乎不合逻辑的时候。
想象一下以下结构:
struct A
{
int32_t a;
int16_t b;
};
sizeof
此结构通常会填充为8个字节,以确保a
在struct 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
是不必要的c
,a
可以放在d
的填充位置和b
和c
相同的位置{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}} 更小。但是,我不能想到这样的事情可能成为问题的情况(即不基于未定义行为的用法)。
答案 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}}似乎要求很多
麻烦,很难找到错误。