结构零初始化是否保证擦除填充区域?

时间:2012-10-24 19:30:51

标签: c struct initialization

假设我有以下结构:

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");

3 个答案:

答案 0 :(得分:11)

是和否。实际标准C11指定:

  

如果具有静态或线程存储持续时间的对象不是   显式初始化,然后:

     
      
  • ...

  •   
  • 如果是聚合,则会初始化每个成员(递归)   根据这些规则,任何填充都被初始化为零位;

  •   

因此,这仅适用于第一个视图中的静态存储对象。但后来又说:

  

如果括号括起的列表中的初始值设定项少于此值   是聚合的元素或成员,或者是一个或多个字符   string literal用于初始化已知大小的数组   是数组中的元素,聚合的其余部分应为   隐式初始化与具有静态存储的对象相同   持续时间。

因此,这意味着未明确初始化的子结构内的填充是零位初始化。

总之,结构中的一些填充保证是零位初始化,有些则不是。我不认为这种混淆是故意的,我会为此提交缺陷报告。

旧版本根本没有。因此,对于大多数现有的编译器,您必须更加小心,因为它们还没有实现C11。但是AFAIR,clang已经为此做了。

另请注意,这仅适用于初始化。填充不一定要在作业中复制。

答案 1 :(得分:6)

C99标准没有规定填充位将设置为零。实际上,它特别提到任何填充位的值都是未指定的,因此不需要在赋值中复制填充。

脚注51至6.2.6.1(6)(n1570):

  

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

新的C2011标准 - 感谢Jens Gustedt用于共享该知识 - 指定静态或线程存储持续时间内没有显式初始化的对象中的填充位初始化为0.

仍无法保证作业。

答案 2 :(得分:2)

  

我的问题是,标准保证的这些填充位是否由语句初始化为零:

没有

未指定填充的值:

  

(C99,6.2.6.1p6)“当一个值存储在结构或联合类型的对象中时,包括在一个成员对象中,对应于任何填充字节的对象表示的字节采用未指定的值”

编辑:请参阅Jens Gustedt answer,C11现在保证在(罕见)特定情况下将填充设置为0