C语言允许实现在结构体(但不是数组)中插入填充以确保所有字段都对目标有用的对齐方式。 如果你将一个结构体清零,然后设置其中一些字段,那么填充位是否都为零? 根据调查结果,36% 的人确定会这样,29% 的人不知道。根据编译器(和优化级别),可能会或可能不会。
这并不完全清楚,所以我查阅了标准。ISO/IEC 9899 在 §6.2.6.1 中说明:
当一个值被存储在结构体或联合类型的对象中,包括成员对象时,与任何填充字节对应的对象表示的字节取未指定值。
同样在 §6.7.2.1 中也有相关说明:
位域在一个单元内的分配顺序(从高位到低位或从低位到高位)是由实现定义的。可寻址存储单元的对齐方式未指定。
我突然想起来最近实现了某种类型的黑客,其中我使用了由位域拥有但未声明的字节部分。大致是这样的:
/* This struct is always allocated on the heap and is zeroed. */
struct some_struct {
/* initial part ... */
enum {
ONE,
TWO,
THREE,
FOUR,
} some_enum:8;
unsigned char flag:1;
unsigned char another_flag:1;
unsigned int size_of_smth;
/* ... remaining part */
};
由于结构不在我控制之下,所以我无法更改它,但我急需通过它传递一些信息。因此,我计算了相应字节的地址,如下:
unsigned char *ptr = &some->size_of_smth - 1;
*ptr |= 0xC0; /* set flags */
然后我以同样的方式检查了标志。
另外,我应该提到目标编译器和平台已经定义,因此这不是跨平台的事情。但是,当前问题仍然存在:
我能否依赖于结构体(在堆中)的填充位在
memset
/kzalloc
/等操作之后仍将保持为零,并且在一些后续使用之后仍将保持为零?(这篇文章没有揭示标准和进一步使用结构体的保障)。那么,在栈上清零的结构体如= {0}
呢?如果是的话,这是否意味着我可以安全地在C语言中使用“未命名”/“未声明”的位域部分在各个地方传输一些信息(不同的平台、编译器等)?(如果我确定没有人疯狂地尝试在这个字节中存储任何东西)。
memset
会设置整个范围,而不关心其内容。 - Weather Vanen
个字符的联合体,其中n
是结构体的大小。你可以进行一次n
== sizeof(struct) 的检查以确保正确性,然后在需要时将n
字符数组清零。 - rcgldrmemset
来覆盖结构体填充。虽然您可以在单个机器上使用单个编译器进行实验以确定其实现行为-但无法保证其适用于任何其他机器或编译器。 - David C. Rankin