11

假设我有以下结构:

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

3 回答 3

11

是和不是。实际标准 C11 规定:

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

  • ……

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

因此,这仅适用于静态存储对象,乍一看。但后来它又说:

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

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

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

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

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

于 2012-10-24T19:45:27.240 回答
6

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

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

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

新的 C2011 标准 - 感谢Jens Gustedt分享该知识 - 指定静态或线程存储持续时间的对象中的填充位在没有显式初始化的情况下初始化为 0。

仍然不能保证分配。

于 2012-10-24T19:33:30.987 回答
2

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

不。

填充的值未指定:

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

编辑:参见 Jens Gustedt的回答,C11 现在保证0在(罕见的)某些情况下将填充设置为

于 2012-10-24T19:40:27.470 回答