Does C initialize structure padding to zero?

2020-03-08 08:41发布

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?

For example the following structure:

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

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' };

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

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.

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

1条回答
Root(大扎)
2楼-- · 2020-03-08 09:32

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.

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.

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;

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

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

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.

查看更多
登录 后发表回答