C是否将结构填充初始化为零?

时间:2016-06-05 12:41:13

标签: c gcc struct initialization

如果C编译器填充结构以使字段与其原始对齐对齐,然后初始化该结构,则填充是否初始化为零?

例如以下结构:

typedef struct foo_t_ {
    int  a;
    char b;
    int  c;
    char d;
} foo_t;

在许多系统上,这个(设计不良)结构的sizeof(foo_t)为16,总共有6个字节的填充,每个字符后3个字节。

如果我们初始化结构如:

foo_t foo = { .a = 1, .b = '2' };

然后字段foo.a将设置为1,foo.b将设置为字符' 2'。未指定的字段(`foo.c'和' foo.d')将自动设置为0.问题是,6个字节的填充会发生什么?那还会自动设置为0吗?还是未定义的行为?

用例是我将计算数据结构的哈希值:

foo_t foo = { .a = 1, .b = '2' };
foo_t bar = { .a = 1, .b = '2' };
uint32_t hash_foo = calc_hash(&foo, sizeof(foo));
uint32_t hash_bar = calc_hash(&bar, sizeof(bar));

我希望确保hash_foohash_bar相同。我可以通过首先使用memset()清除结构然后初始化它来保证这一点,但是使用C初始化似乎更清晰。

在实践中,我系统上的GCC也确实清除了填充,但我不知道这是否有保证。

1 个答案:

答案 0 :(得分:15)

一般情况下,根据C11,对于任何未初始化的对象章节§6.2.6.1/ 6,

  

当值存储在结构或联合类型的对象中时,包括在成员中   object,对象表示的字节,对应于任何填充字节   未指定的值。

但是,如果部分初始化完成,在这种情况下,对于成员的 rest ,初始化就像一个具有静态或线程存储持续时间的对象一样发生然后,引用相同的标准,章节§6.7.9/ 21

  

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

关于具有静态存储持续时间的对象的隐式初始化,第10段

  

如果未初始化具有静态或线程存储持续时间的对象   明确地说:

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

因此,在您的情况下,其余对象的填充保证为0,但不适用于已收到初始化程序的成员。

所以,到处都是,你不应该依赖于隐式初始化0,使用memset()

话虽如此,无论如何,不​​建议(必需)依赖于填充字节(如果有的话)。使用确切的成员变量并根据这些值计算哈希值。