Обработка указателей на пустоту в C

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