https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118403
--- Comment #10 from Jakub Jelinek <jakub at gcc dot gnu.org> --- (In reply to Stephen Hemminger from comment #0) > My understanding is that both should be equivalent. > Reference C99 Standard 6.7.8.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 A union has just one member active at a time. If you don't use designated initializer, then {0} just initializes the first member in there. All the remaining bits are padding. Before C23, padding bits were guaranteed to be cleared only when initializing static storage duration, or when doing the implicit zero initialization of extra members. So, say struct A { char a; /* 7 padding bytes */ long long b; }; struct B { int c; /* 4 padding bytes */ struct A d; }; void foo () { struct B e = { 0 }; // This doesn't guarantee initialization of the 4 padding bytes, // but does guarantee initialization of the 7 padding bytes struct B f = { 0, { 0 } }; // This one doesn't guarantee initialization of any padding bytes, just the fields. struct B g = { 0, { 0, 0 } }; // Neither this. } Now, C23 adds {} initializers and those are also guaranteed to zero padding bits, so ... struct B h = {}; // Guarantees zero initialization of all padding bits struct B i = { 0, {} }; // Guarantees initialization of the 7 padding bytes but not the 4. If you use struct nic_mbx mbx = { }; then all bits including padding are zero initialized, { .msg = { 0 } }; means that .msg field has its first member initialized but doesn't say anything about padding bits. You could say also { .whatever_field_is_largest = { 0 } } and initialize more bits.