Так как вы спросили;) в C есть один инструмент для избежания явного дублирования кода, макросы.Тем не менее, я не вижу способа не повторять хотя бы название типа.Но в C ++ они тоже не могут, поэтому C, по крайней мере, так же хорош:)
Самое простое, что я вижу, это
#define DESIGNATE_NEW(T) \
memcpy(malloc(sizeof(T)), \
&(T const){ __VA_ARGS__ }, \
sizeof(T))
, что даст
Type *t = DESIGNATE_NEW(Type,
.a = 2,
.b = 3,
.c = 5,
);
это имеет несколько преимуществ.
- Он правильно инициализирует все элементы, даже на архитектурах с нестандартными представлениями
0
для типов с плавающей точкой или указателей. - Кроме версии Keith 'itявляется приемлемым «стилем кодирования», так как это просто выражение, которое выглядит как инициализация, и любой должен немедленно визуально захватить то, что должен делать второй фрагмент кода.
Примечание: соблюдайте const
вмакрос, это позволяет сложить несколько экземпляров составного литерала, если компилятор решит, что это актуально.Также есть способы иметь вариант, в котором список указателей является необязательным, см. P99 ниже.
Недостатком является memcpy
, и я был бы счастлив с назначением.Во-вторых, нет проверки на malloc
перед использованием результата, но, возможно, можно столкнуться с какой-то странностью, чтобы код красиво завершился.
В P99 Я немного идудругой путь.Там у нас всегда есть функция инициализации для типа, что-то вроде
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;
}
, которая может быть использована с помощью магии макроса для предоставления аргументов по умолчанию для a
, b
и c
, если они опущены.Тогда вы можете просто использовать что-то вроде
Type *t = P99_NEW(Type, 1, 2, 3);
в своем коде приложения.Это лучше, поскольку позволяет избежать разыменования указателя при сбое вызова malloc
.С другой стороны, это вновь вводит порядок инициализаторам, поэтому тоже не идеален.