#c #pointers #data-structures #void-pointers
Вопрос:
Я создаю код на языке Си для обработки разреженных матриц и хочу максимально модульизировать свой код.
Я заметил, что пару раз мне нужно пройти, пока я не найду предыдущий узел (о, я использую связанные списки для построения матрицы), и я хочу создать функцию многократного использования.
У меня в коде есть 4 структуры, все они имеют переменные first
, last
или next
если это дочерняя структура, у которой нет роли заголовка.
Я думал, что такой код:
void *iterateUntilNext(void *header, void *child) { void *walker = header-gt;first; while (walker-gt;next != child) { walker = walker-gt;next; } return walker; }
Но я получил эту ошибку: expression must have pointer-to-struct-or-union type but it has type "void *"
Есть ли какой-нибудь способ заставить это работать, или я слишком много мечтаю?
Комментарии:
1. Приведите его к указателю типа, на который он, как ожидается, будет указывать. Или работайте с этим типом, а
void*
не полностью вниз.2. Как указатель на тип не может иметь членов. Мой совет — не пытайтесь быть слишком универсальными. Это никогда не работает.
3.
header
указывает на неизвестный тип, как компилятор узнает, что этоfirst
за поле?4. Обычный шаблон создания «универсальных» типов данных заключается в обеспечении доступа и других операций во время создания структуры данных. Но это относительно широкая тема, которую следует осветить в комментариях. Может быть, кто-нибудь напишет это в качестве ответа…
5. @0___________ что ж, я сожалею, если мой вопрос не способствует сообществу. Действительно, я в некотором роде новичок в С. Если вы все считаете, что вопрос должен быть закрыт, я его закрою. Но обратите внимание, что нет ни одного человека, который родился бы, зная все. Также имейте в виду, что ваш последний комментарий был не таким уж вежливым. Но спасибо за отзыв 🙂
Ответ №1:
ООП
Определите базовую структуру, такую как
#define list_item_interface list_item *first; list_item *next; typedef struct list_item { list_item_interface } list_item;
и «выводите» свои пользовательские элементы, такие как
typedef struct custom_list_item { list_item_interface //needs to be the first entry //other members/fields } custom_list_item;
затем определите свои «общие» функции, такие как
list_item* iterate(list_item *header, list_item *child) { /*...*/ }
назови это так
custom_list_item *header, *child; iterate((list_item*) header, (list_item*) child);
GCC — Расширение
Принимает любой тип, который предоставляет поля first
и next
того же типа.
#define LIST_ITEM_ITERATE(HEADER, CHILD) ({ __auto_type HEADER_ = (HEADER); __auto_type CHILD_ = (CHILD); __auto_type WALKER = HEADER_-gt;first; while (WALKER-gt;next != CHILD_) WALKER = WALKER-gt;next; WALKER; )}
Комментарии:
1. UB — строгие правила сглаживания.
2. @0___________ Как насчет стандарта C11, раздел 6.5 Выражения, параграф 7: тип агрегата или объединения, который включает в себя один из вышеупомянутых типов среди своих членов (включая, рекурсивно, члена субагрегата или содержащегося объединения) . Нравится:
struct custom_list_item { list_item *base; /*...*/ };