sourcejedi
sourcejedi

Reputation: 3271

Does standard C accept `{0}` as an initializer for any struct?

This is often suggested, as a way to initialize a struct to zero values:

struct foo f = {0};

It is also mentioned that {} could be used under gcc, but that this is not standard C99.

I wonder if this works for a struct whose layout may vary outside my control. I'm anxious because 0 is not a valid initializer for an array or struct. However gcc --std=c99 (gcc-8.1.1-1.fc28.x86_64) seems to accept {0} even in such cases.

Question Does C99 accept {0} as an initializer for any struct?

(Or a later C standard? Or contrawise, is there any reason not to rely on this? Are there compilers where {0} could cause an error or a warning that would discourage its use?)

What I have tried

gcc warnings (enabled with -Wall) suggest that this is some form of edge case in the standard, where gcc has been forced to accept 0 as an initializer for any type of struct field, but it will warn about it unless you are using the common {0} idiom.

struct a { int i; };
struct b { struct a a; struct a a2; };
struct c { int i[1]; int j[1]; };

struct a a = {0}; /* no error */
struct b b = {0}; /* no error */
struct c c = {0}; /* no error */

/* warning (no error): missing braces around initializer [-Wmissing-braces] */
struct b b2 = {0, 0};
/* warning (no error): missing braces around initializer [-Wmissing-braces] */
struct c c2 = {0, 0};

struct a a2 = 0; /* error: invalid initializer */
int i[1] = 0; /* error: invalid initializer */

Upvotes: 7

Views: 4293

Answers (3)

sourcejedi
sourcejedi

Reputation: 3271

Yes.

Inside an initialization list, "missing braces around initializer" is allowed by the standard. C99:

If the aggregate or union contains elements or members that are aggregates or unions, these rules apply recursively to the subaggregates or contained unions. If the initializer of a subaggregate or contained union begins with a left brace, the initializers enclosed by that brace and its matching right brace initialize the elements or members of the subaggregate or the contained union. Otherwise, only enough initializers from the list are taken to account for the elements or members of the subaggregate or the first member of the contained union; any remaining initializers are left to initialize the next element or member of the aggregate of which the current subaggregate or contained union is a part.

Upvotes: 2

Bathsheba
Bathsheba

Reputation: 234655

= {0} tells the compiler to perform aggregate initialisation, and the first member is set to the value that it would be assumed if the struct had static storage duration.

In such an aggregate initialisation, if there are fewer initialisers in the list than there are members in the struct, then each member not explicitly initialised is default-initialised.

So yes, a C compiler will accept = {0} as an initialiser for any struct.

Upvotes: 2

user743382
user743382

Reputation:

Yes, this is perfectly valid.

All scalar types (integer types, floating point types and pointer types) accept 0 as an initialiser. This is not a fundamental property of scalar types, but it happens to apply to all of them.

All aggregate types (arrays and structures) and union types will have at least one member or element. Either the first member or element is a scalar type, or it is another aggregate or union type. If the former, that makes {0} a valid initialiser. If the latter, apply the same logic: that too will have at least one member or element. Either that is a scalar type, or it is another aggregate or union type. Keep going. There is no way to have infinitely nested structures, so you'll always end up at a scalar type.

Non-standard language extensions could invalidate some of these assumptions. For instance, a language extension could define strongly-typed enumeration types which do not accept 0 as an initialiser, or empty structures, or zero-length arrays.

Upvotes: 7

Related Questions