Reputation: 44739
From experimentation (in Clang and GCC, with -O2 and -O0) is seems that in the following code
typedef struct foo_s { int i; int j; } foo_t;
int main(void) {
foo_t foo = {.i = 42};
...
foo.j is automatically zero.
Is the guaranteed by C99 onwards, or is it a compiler specific implementation detail?
Note: I've even tried writing 0xFFs to invalid memory below the stack, at the address which foo is later given.
Update: There are a couple of comments stating that this is just because the memory below the stack happens to contain zeros. The following code makes sure this is not the case, and may prove that GCC -O0 is zeroing memory.
The offsets of -7 and -6 are compiler dependent. They needed to be different in Clang.
typedef struct foo_s { int i; int j; } foo_t;
int main(void) {
int r;
int *badstack0 = &r - 7;
int *badstack1 = &r - 6;
*badstack0 = 0xFF; // write to invalid ram, below stack
printf("badstack0 %p, val: %2X\n", badstack0, *badstack0);
*badstack1 = 0xEE; // write to invalid ram, below stack
printf("badstack1 %p, val: %2X\n", badstack1, *badstack1);
// struct test
foo_t foo = {.i = 42};
printf("&foo.i %p\n", &foo.i);
printf("&foo.j %p\n", &foo.j);
printf("struct test: i:%i j:%i\n", foo.i, foo.j);
return 0;
}
Output:
badstack0 0x7fff221e2e80, val: FF
badstack1 0x7fff221e2e84, val: EE
&foo.i 0x7fff221e2e80
&foo.j 0x7fff221e2e84
struct test: i:42 j:0
Upvotes: 4
Views: 469
Reputation: 213513
C guarantees that as long as at least one member of an array/struct/union* is initialized explictily, then all other members will be initialized as if they had static storage duration, as cited in Daniel Fischer's answer. In other words, all the other members are set to zero or NULL automatically.
The storage type of the array/struct/union matters not, they are initialized according to the same rule no matter if they have automatic or static storage duration.
This is not something unique to C99 or later, C has always had this requirement. All conforming C compilers follow this rule, it is normative and not implementation-defined.
This has nothing to do with "debug release" zero outs.
As a matter of fact, this rule is the explanation why you can zero a whole array by writing
int array[100] = {0}
.
This code means, "initialize the first element to zero, and initialize the 99 remaining ones as if they had static storage duration, ie make them zero too".
(*) Those three types are formally named "aggregate type" in the C standard.
Upvotes: 4
Reputation: 183858
If you provide any initialisers, the members not explicitly mentioned are initialised as if they were static. That's guaranteed by the standard in 6.7.9 (19):
The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject; all subobjects that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration.
(Emphasis added by me)
If you don't initialise any member, the values of all members are indeterminate.
Upvotes: 9