结构零初始化是否保证擦除填充区域?
假设我有以下结构:
typedef struct { unsigned field1 :1; unsigned field2 :1; unsigned field3 :1; } mytype;
前3位可用,但sizeof(mytype)
将返回4
,这意味着29位填充。 我的问题是,标准保证的这些填充位是否由语句初始化为零:
mytype testfields = {0};
要么:
mytype myfields = {1, 1, 1};
这样可以安全地执行以下memcmp()
,假设位4..29为零,因此不会影响比较:
if ( memcmp(&myfields, &testfields, sizeof(myfields)) == 0 ) printf("Fields have no bits set\n"); else printf("Fields have bits set\n");
是的,不是。 实际标准C11规定:
如果未显式初始化具有静态或线程存储持续时间的对象,则:
….
如果是聚合,则根据这些规则初始化(递归)每个成员,并将任何填充初始化为零比特;
因此,这仅适用于第一个视图中的静态存储对象。 但后来又说:
如果括号括起的列表中的初始值设定项少于聚合的元素或成员,或者用于初始化已知大小的数组的字符串文字中的字符数少于数组中的元素,则聚合的其余部分应为隐式初始化与具有静态存储持续时间的对象相同。
因此,这意味着未明确初始化的子结构内的填充是零位初始化。
总之,结构中的一些填充保证是零位初始化,有些则不是。 我不认为这种混淆是故意的,我会为此提交一份缺陷报告。
旧版本根本没有。 因此,对于大多数现有的编译器,您必须更加小心,因为它们还没有实现C11。 但AFAIR,clang已经为此做了。
另请注意,这仅适用于初始化。 填充不一定要在作业中复制。
C99标准未指定填充位将设置为零。 实际上,它特别提到任何填充位的值都未指定,因此不需要在赋值中复制填充。
脚注51至6.2.6.1(6)(n1570):
因此,例如,结构分配不需要复制任何填充比特。
新的C2011标准 – 感谢Jens Gustedt分享该知识 – 指定静态或线程存储持续时间的对象中的填充位而没有显式初始化被初始化为0。
仍无法保证作业。
我的问题是,标准保证的这些填充位是否由语句初始化为零:
没有。
填充的值未指定:
(C99,6.2.6.1p6)“当一个值存储在结构或联合类型的对象中时,包括在一个成员对象中,对应于任何填充字节的对象表示的字节采用未指定的值”
编辑:请参阅Jens Gustedt的回答 ,C11现在保证在某些情况下(稀少)填充设置为0