Какой способ лучше для создания структур, не зависящих от типа в C?
Я пытаюсь написать некоторые общие структуры. По сути, для моих целей мне нужны шаблоны C++, но поскольку я пишу на C, шаблоны не рассматриваются. В настоящее время я рассматриваю 2 способа достижения того, чего я хочу.
Способ 1: использовать препроцессор. Вот так:
#define DEFINE_PAIR(T) typedef struct Pair_##T{ \
T x; \
T y; \
} Pair_##T
DEFINE_PAIR(int);
int main(){
Pair_int p;
return 0;
}
Очевидным недостатком является то, что вы должны вызывать макрос перед использованием типа. Вероятно, есть и другие недостатки, на которые, я надеюсь, вы укажете.
Способ 2: просто используйте void-указатели, вот так:
typedef struct Pair{
void* x;
void* y;
} Pair;
Очевидно, что этот подход небезопасен (я мог бы легко передать пару строк в функцию, ожидающую пару удвоений), плюс код, выполняющий освобождение, становится намного более запутанным при таком подходе.
Я хотел бы услышать ваши мысли по этому поводу. Какой из двух методов лучше / хуже и почему? Есть ли какой-либо другой метод, который я мог бы использовать для написания общих структур в C?
Благодарю.
3 ответа
Если вы планируете использовать только примитивные типы данных, то ваше оригинальное решение на основе макросов кажется достаточно изящным. Однако, когда вы начнете хранить пары указателей на непрозрачные типы данных со сложными структурами, которые предназначены для использования при передаче указателей между функциями, такими как:
complex_structure_type *object = complex_structure_type_init();
complex_structure_type_set_title(object, "Whatever");
complex_structure_type_free(object);
тогда ты должен
typedef complex_structure_type *complex_structure_type_ptr;
чтобы
DEFINE_PAIR(complex_structure_type_ptr);
так что вы можете
Pair_complex_structure_type_ptr p;
а потом
p.x = object;
Но это всего лишь немного больше работы, поэтому, если вы чувствуете, что это работает для вас, пойти на это. Вы могли бы даже собрать свой собственный препроцессор, который проходит через код, вытаскивает что-нибудь вроде Pair_whothing и затем добавляет DEFINE_PAIR(что угодно) для препроцессора C. В любом случае, это определенно хорошая идея, которую вы представили здесь.
Лично я бы просто использовал указатели void и забыл о строгой безопасности типов. C просто не имеет такого же механизма безопасности, как другие языки, и чем больше у вас возможностей забыть что-то, тем больше ошибок вы случайно создадите.
Удачи!
Отмечая, что шаблоны в C++ предоставляют язык для написания кода, вы можете просто подумать о создании кода с помощью более мощного инструмента, чем c-препроцессор.
Теперь это добавляет еще один шаг к вашей сборке и делает сборку зависимой от других сборов (если вы не хотите писать свой собственный генератор в c...), но это может обеспечить гибкость и безопасность типов, которые вы желаете.
Это почти то же самое, но это немного более ловко:
#define PAIR_T(TYPE) \
struct { \
TYPE x; \
TYPE y; \
}
typedef PAIR_T(int) int_pair;
typedef PAIR_T(const char *) string_pair;
int main(void)
{
int_pair p = {1, 1};
string_pair sp = {"a", "b"};
}