LINUX.ORG.RU

[C]Поиск узла в списке

 


0

1

Доброй ночи. Имеется следующая структура для организации двусвязного списка:

typedef struct _DList DList;
struct _DList
{
  void *data;
  DList *next;
  DList *prev;
};
С помощью структуры организованы несколько списков, каждый из которых указывает на структуры различных типов. И каждый из узлов этих списков содержит уникальный идентификатор - запись int UID.

И возник вопрос - можно ли как-то организовать поиск элемента в списках с помощью одной функции, а не писать для каждого типа структуры свою функцию поиска?

Спасибо.


1. Сделай поле с одинаковым смещением во всех структурах.

2. Сделай общую структуру:

struct generic {
    int id;
    void *data;
};

и пихай ее в список, а не data.

3.

struct _DList
{
  int id;
  void *data;
  DList *next;
  DList *prev;
};

bk_ ★★
()
Ответ на: комментарий от bk_

1. Сделай поле с одинаковым смещением во всех структурах.

Думал над этим вариантом. Но почему-то мне показалось, что это для прикладного уровня довольно некрасивое решение.
За второй вариант спасибо. Подумаю как от него плясать.

mkam
() автор топика

В некоторых случаях в качестве UID можно использовать значение самого указателя (в твоем случае data).

m0rph ★★★★★
()
Ответ на: комментарий от mkam

Думал над этим вариантом. Но почему-то мне показалось, что это для прикладного уровня довольно некрасивое решение.

В структуре XEvent так сделано. Там union из инта с типом и кучи структур для разного содержимого в зависимости от типа: http://tronche.com/gui/x/xlib/events/structures.html

gentoo_root ★★★★★
()
Ответ на: комментарий от mkam

Я подумал, и бы сделал так:

struct generic {
  int id;
};

struct my1 {
  struct generic g;
  ...
};

struct my2 {
  struct generic g;
  ...
};

DList *d = ...;
struct generic *aa = d->data;
struct my1 *m1 = aa;

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

bk_ ★★
()

Можно взять sys/queue.h (man 3 queue), там есть макрос LIST_FOREACH:

    struct struct1 *p1;
    struct struct2 *p2;

    LIST_FOREACH(p1, &head1, entries1)
        // ... use p1 ...

    LIST_FOREACH(p2, &head2, entries2)
        // ... use p2 ...

или написать упрощённую его версию:

#include <sys/queue.h>

#define FOR_LIST(TYPE, POINTER, HEAD)                                   \
    for (TYPE *(POINTER) = (HEAD).lh_first;                             \
         (POINTER) != NULL;                                             \
         (POINTER) = (POINTER)->entries.le_next)

...

    FOR_LIST(struct struct1, p, head1)
        // ... use p ...

    FOR_LIST(struct struct2, p, head2)
        // ... use p ...

тут struct struct1 и struct struct1 должны иметь поля entries.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Кажется это именно то, что мне хотелось.
Спасибо всем ответившим!

mkam
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.