Какой способ лучше для создания структур, не зависящих от типа, в C? - PullRequest
7 голосов
/ 15 августа 2011

Я пытаюсь написать некоторые общие структуры. По сути, для моих целей мне нужны шаблоны 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;

Очевидно, что этот подход небезопасен (я мог бы легко передать пару строк в функцию, ожидающую пару значений типа double), плюс код, выполняющий освобождение, становится намного более запутанным при таком подходе.

Я хотел бы услышать ваши мысли по этому поводу. Какой из двух методов лучше / хуже и почему? Есть ли другой метод, который я мог бы использовать для написания общих структур в C?

Спасибо.

Ответы [ 3 ]

4 голосов
/ 15 августа 2011

Если вы планируете использовать только примитивные типы данных, то ваше оригинальное решение на основе макросов кажется достаточно изящным. Однако, когда вы начинаете хранить пары указателей на непрозрачные типы данных со сложными структурами, которые предназначены для использования при передаче указателей между функциями, такими как:

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 просто не имеет такого же механизма безопасности, как другие языки, и чем больше у вас возможностей забыть что-то, тем больше ошибок вы случайно создадите.

Удачи!

2 голосов
/ 16 августа 2011

Учитывая, что шаблоны в c ++ предоставляют язык для написания кода, вы можете просто подумать о создании кода с помощью более мощного инструмента, чем препроцессор c.

Теперь это добавляет еще один шаг к вашей сборке и делает сборку зависимой от других сборов (если вы не хотите писать свой собственный генератор в c ...), но это может обеспечить гибкость и безопасность типов, которые вы пожелаете.

1 голос
/ 20 мая 2014

Это почти то же самое, но немного шустрее:

#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"};
}
...