Anyway, this smart pointer interface doesn't have to dictate any such a dialect to its users; it can just have C++ as a target. It was just a thought.
When I work in a restricted dialect of C that is portable to C++ compilers, I have better type safety: safer treatment of void *, string literals that are const-qualified, type-safe enumerations, and safer casting operators (reinterpret_cast, const_cast, static_cast) which I can hide behind macros that work in C or C++. On the other hand, I don't have C99 designated initializers. It would be great to have both!
If I had some static data that would so greatly benefit from these initializers that I cannot do without them, I might put that into a separate module that is compiled as C99. Not terribly convenient if you just want to throw a handful of static functions into an operations structure, though or whatever.
There are solutions for better initialization available when you're working in C90. For each structure that is instantiated somewhere with an initializer, you can write an initializer macro instead. The macro is close to the structure definition and is maintained together. If you need a few different ways of initializing the same aggregate, then several macros can be provided that have different argument lists and different defaulting.
When a new member is added (that isn't defaulted), the macros get a new argument. Either way, their expansions are carefully edited to initialize that member. The macro bodies of such initializer macros provide a complete initializer, covering every member explicitly.
If the addition of a new member results in a new macro argument, the existing macro calls then do not compile; they have to be maintained. (Whereas naked initializers just keep compiling and become incorrect when structure members shuffle around: the nasty problem we want to avoid.) Ultimately this functional approach is more disciplined and safer than designated initializers.
From a safety point of view, designated initializers only solve the problem of the wrong initial value going to the wrong aggregate member (that by chance has a suitable type to accept that initializer without a diagnostic). Functional initializers take a more complete approach of specifying the initialization in terms of constructor-like parameters, which are required, with the possibility of defaulting other elements to values other than zero.
The one thing designated initializers do which cannot be beaten, is that you can declare a million element array and initialize element [999999] to 42, statically. This may be a bad idea; some linkage models may actually implement that by adding one million words of initialized data to your executable image. Whereas if you leave it uninitialized, and stick in the 42 at run-time, the whole object is in the "BSS" section.