As you asked;) in C there is one tool to avoid explicit duplication of code, macros. Nevertheless, I see no way not to repeat at least the type name. But in C ++ they can't either, so C is at least as good :)
The lightest I see
#define DESIGNATE_NEW(T) \ memcpy(malloc(sizeof(T)), \ &(T const){ __VA_ARGS__ }, \ sizeof(T))
which would give
Type *t = DESIGNATE_NEW(Type, .a = 2, .b = 3, .c = 5, );
This has several advantages.
- Initializes all elements correctly, even on architectures, standard
0 representations for float types or pointers. - Unlike the Keith version, this βcoding styleβ is acceptable, because it is just an expression that looks like initialization, and someone should immediately visually display what the second code skippet should do.
Note. Observe the const in the macro, this allows you to discard multiple instances of the composite literal if the compiler decides that this is relevant. There is also a means to have an option where a list of pointers is optional, see Below P99.
The downside is memcpy , and I would be happier with the appointment. Secondly, there is no malloc failure check before using the result, but you can probably run into some kind of weirdness in order to get good code.
In P99, I am a little different. There we always have an initialization function for the type, something like
inline Type* Type_init(Type* t, int a, int b, int c) { if (t) { *t = (Type const){ .a = a, .b = b, .c = c }; } return t; }
which macros can be made to provide default arguments for a , b and c if omitted. Then you can just use something like
Type *t = P99_NEW(Type, 1, 2, 3);
in your application code. This is better since when calling malloc it was not possible to delete the pointer to the pointer. On the other hand, this reintroduces the order to the initializers, therefore is also not perfect.