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

Ben*_*enj 11 c struct initialization

假设我有以下结构:

typedef struct
{
    unsigned field1 :1;
    unsigned field2 :1;
    unsigned field3 :1;
} mytype;
Run Code Online (Sandbox Code Playgroud)

前3位将可用,但sizeof(mytype)将返回4,这意味着29位填充.我的问题是,标准保证的这些填充位是否由语句初始化为零:

mytype testfields = {0};
Run Code Online (Sandbox Code Playgroud)

要么:

mytype myfields = {1, 1, 1};
Run Code Online (Sandbox Code Playgroud)

这样,memcmp()假设位4..29为零,执行以下操作是安全的,因此不会影响比较:

if ( memcmp(&myfields, &testfields, sizeof(myfields)) == 0 )
    printf("Fields have no bits set\n");
else
    printf("Fields have bits set\n");
Run Code Online (Sandbox Code Playgroud)

Jen*_*edt 11

是的,不是.实际标准C11规定:

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

  • ....

  • 如果它是一个聚合,则根据这些规则初始化(递归)每个成员,并将任何填充初始化为零比特;

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

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

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

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

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

另请注意,这仅适用于初始化.填充不一定要在分配时复制.

  • 我认为你应该添加C11段落的开头*如果没有显式初始化具有自动存储持续时间的对象,则其值是不确定的.如果没有显式初始化具有静态或线程存储持续时间的对象,则:*这不保证`mytype testfields = {0}中的填充;`设置为'0`. (4认同)
  • @啊,确切地说.我发现这很烦人,我现在在https://gustedt.wordpress.com/2012/10/24/c11-defects-initialization-of-padding/上写了更多内容 (3认同)
  • +1,有趣的是我没有意识到这种变化. (2认同)

Dan*_*her 6

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

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

因此,例如,结构分配不需要复制任何填充比特.

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

仍无法保证作业.

  • 嗯,这相当暗示`memcmp()`是一种不安全的方法来比较任何有填充的结构,虽然不是吗? (2认同)