C是否将结构填充初始化为零? [英] Does C initialize structure padding to zero?

查看:129
本文介绍了C是否将结构填充初始化为零?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果C编译器填充结构以使字段与它们的本机对齐方式对齐,然后对该结构进行初始化,则填充是否初始化为零?

If a C compiler pads a structure in order to align the fields to their native alignment, and that structure is then initialized, is the padding initialized to zero?

例如以下结构:

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

在许多系统上,这种(设计欠佳)的结构的sizeof(foo_t)为16,总共填充6个字节,每个字符后3个字节.

On many systems this (poorly designed) structure would have a sizeof(foo_t) of 16, with a total of 6 bytes of padding, 3 bytes after each of the chars.

如果我们像这样初始化结构:

If we initialize the structure like:

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

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

then the fields foo.a will be set to 1 and foo.b will be set to the character '2'. The unspecified fields (`foo.c' and 'foo.d') will automatically be set to 0. The question is, what happens to the 6 bytes of padding? Will that also automatically be set to 0? or is it undefined behavior?

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

The use case is that I will be calculating hashes of data structures:

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初始化似乎更干净.

and I want to be sure that hash_foo and hash_bar are the same. I could guarantee this by first using memset() to clear the structures, then initializing them, but it seems cleaner to use C initialization instead.

实际上,我系统上的GCC也会清除填充,但是我不知道这样做是否可以保证.

In practice, GCC on my system does clear the padding as well, but I don't know if that is guaranteed.

推荐答案

通常,按照C11的规定,对于任何未初始化的对象章节§6.2.6.1/6,

In general, As per C11, for any uninitialized object chapter §6.2.6.1/6,

当值存储在结构或联合类型的对象(包括成员)中时 对象,与任何填充字节对应的对象表示形式的字节 未指定的值.

When a value is stored in an object of structure or union type, including in a member object, the bytes of the object representation that correspond to any padding bytes take unspecified values.

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

But, if the partial initialization is done, in that case, for rest of the members, the intialization happens as if an object that has static or thread storage duration, then, quoting the same standard, chapter §6.7.9/21

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

If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.

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

and regarding the implicit initialization of objects with static storage duration, paragraph 10

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

If an object that has static or thread storage duration is not initialized explicitly, then:

  • 如果它是一个聚合,则根据这些规则(递归地)初始化每个成员, 并将所有填充都初始化为零位;
  • if it is an aggregate, every member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;

因此,在您的情况下,确保其余对象的填充为0,但对于已收到初始化程序的成员,则填充为0.

So, in your case, padding for the remaining objects are guaranteed to be 0, but not for the members which has received the initializers.

因此,总的来说,您不应该依赖于隐式初始化为0,而是使用memset().

So, all over, you should not depend on an implicit initialization of 0, use memset().

话虽这么说,但无论如何,不​​建议( required )依赖于填充字节.使用确切的成员变量,并根据这些值计算哈希值.

That being said, in anyway it's not recommended (required) to depend on padding bytes, if any. Use the exact member variables and calculate the hash based on those values.

这篇关于C是否将结构填充初始化为零?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆