Here is something in C99 that seems like a great idea and improvement and is often lauded, yet turns out to be ... meh: designated initializers. Sure, these address problems like the wrong function pointer being assigned when the positional order is wrong: the programmer version of buttoning up your shirt wrong.  These things are even Torvalds-approved and used in the Linux kernel (whose compilation will complain, if you mix declarations and statements, that they are not a C90 feature!!!)<p>But here is the thing: all the initialization comes from the initializer, not from the struct type, and the only default value you get is the good old 0 (0 integer, 0.0 floating point, null pointer).  So, if you want any other default, designated initializers are basically useless.<p>The designers of a data type want to provide initialization mechanisms with defaults which they control from the site of the definition of the type.  We can do that in C90 with macros.  Macros ensure that everything is initialized. If we add a member that must be initialized with a non-default value everywhere, we add a parameter to the macro, and the compiler will catch all the places where the macro is called with the old number of parameters.<p><pre><code>   struct foo {
     char *name;
     int bogosity;
   };

   #define foo_anon_init(bogosity) { &quot;anon&quot;, bogosity }
   #define foo_init(name, bogosity) { name, bogosity }
</code></pre>
You provide all the variants in one place which do all the forms of defaulting which you need, and which stick the parameters into the correct place, and then just use them everywhere else.<p>Even if you have designed initializers, it&#x27;s still good idea to wrap initialization that way; they don&#x27;t replace its benefits.<p>Suppose I add a frobosity member, and there is no obvious way to default it. All the places where the structure is instantiated have to be analyzed case by case to choose the appropriate value. Designated initializers (alone) won&#x27;t help; we add the member to the struct and nothing happens. It defaults to zero everywhere it is not explicitly mentioned with a designated or positional initializer. With the macros we just add it as a parameter:<p><pre><code>   struct foo {
     char *name;
     int bogosity, frobosity;
   };

   #define foo_anon_init(bogosity, frobosity) \
   { &quot;anon&quot;, bogosity, frobosity }
   #define foo_init(name, bogosity, frobosity) \
   { name, bogosity, frobosity }
</code></pre>
Now &quot;make -k&quot; and fix all the places where the macros are called with too few arguments, choosing a value for the frobosity.<p>With designated initializers we can of course do:<p><pre><code>   #define foo_anon_init(bogosity, frobosity) \
   { .name = &quot;anon&quot;, .bogosity = bogosity, \
     .frobosity = frobosity }
</code></pre>
But that brings very little to the table when we&#x27;ve gathered all this stuff in one place (which alone reduces mistakes) and we are initializing every member to a nonzero value.<p>Languages that have keyword initializers are great when the class supplies defaults for all the ones that the constructor doesn&#x27;t specify.<p><pre><code>   (make-instance &#x27;foo :frobosity 42) ;; 50 other slots defaulted for us
</code></pre>
If you want to change a default, you don&#x27;t want to go to all the places where the type is instantiated and update the initializer!!!