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.
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.