fadedbee
fadedbee

Reputation: 44739

Are unmentioned struct fields *always* initialised to zero (i.e. when the struct is on the stack)?

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

Answers (2)

Lundin
Lundin

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

Daniel Fischer
Daniel Fischer

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

Related Questions