已经提供给您的解决方案的替代方案涉及将类型标识符连接到所涉及的类型(我还应该在我的解决方案中命名该结构,但我不会更正我的同事@AmitBerger,给出了很好的解决方案)
此解决方案允许您将节点链接到多个列表(不是通过引用),并允许您创建一个全局列表(或者,通常不是动态分配的内存),甚至是它的混合。
我的解决方案有点不同。前段时间,我根据从 linux 内核中提取的一个想法写了一个链接列表的解决方案,我将在下面复制。解决方案正好相反,只需定义一个节点结构,并将其嵌入(该节点可以属于列表的次数)到您类型的结构中。这样,您可以拥有属于多个列表的节点,只有在您最终结束存储对实际节点的引用时才能拥有这些列表(如果您实施其他答案提出的解决方案)。 (这在内核中的数据结构中经常使用,无论是 linux 还是其他)
#ifndef LISTS_H
#define LISTS_H
#include <assert.h>
typedef struct LNODE_S {
struct LNODE_S *n_prev;
struct LNODE_S *n_next;
} LNODE_T, *LNODE_P;
typedef struct LIST_S {
size_t l_size;
LNODE_P l_first;
LNODE_P l_last;
} LLIST_T, *LLIST_P;
#ifndef OFFSETOF
/* gives the offset of field f in type T */
#define OFFSETOF(T,f) ((char*)&(((T*)0)->f)-(char*)0)
#endif
/* initialize fields of list L */
#define LIST_INIT(L) do{ \
(L)->l_size=0; \
(L)->l_first=(L)->l_last=0; \
}while(0)
/* list declaration (with initializer) */
#define LIST_DECLARE(L) \
LLIST_T L={ \
.l_size=0, \
.l_first=0, \
.l_last=0\
}
/* get first, next, prev or last nodes of a list */
#define LIST_FIRST(L) ((L)->l_first)
#define LIST_LAST(L) ((L)->l_last)
#define LIST_NEXT(N) ((N)->n_next)
#define LIST_PREV(N) ((N)->n_prev)
/* get the list node correspondent to list tagged F of struct element passed as E */
#define LIST_NODE(E,F) ((LNODE_P)&(E)->F)
/* get the corresponding struct element to a list node N (embedded as field F) */
#define LIST_ELEMENT(N,T,F) ((N)?(T*)((char*)(N)-OFFSETOF(T,F)):0)
/* first element of list L (tagged as L field in T) of type T */
#define LIST_FIRST_ELEMENT(L,T,F) (LIST_ELEMENT(LIST_FIRST(L),T,F))
#define LIST_LAST_ELEMENT(L,T,F) (LIST_ELEMENT(LIST_LAST(L),T,F))
#define LIST_NEXT_ELEMENT(E,T,F) (LIST_ELEMENT(LIST_NEXT(LIST_NODE(E,F)),T,F))
#define LIST_PREV_ELEMENT(E,T,f) (LIST_ELEMENT(LIST_PREV(LIST_NODE(E,F)),T,F))
/* for(;;) loop, you add the body after the macro call. Nodes */
#define LIST_FOREACH(p, L) for(p=LIST_FIRST(L);p;p=LIST_NEXT(p))
#define LIST_FORBACK(p, L) for(p=LIST_LAST(L);p;p=LIST_PREV(p))
/* idem, but you get the element of type T reference */
#define LIST_FOREACH_ELEMENT(p,L,T,F) for(p=LIST_FIRST_ELEMENT(L,T,F);p;p=LIST_NEXT_ELEMENT(p,T,F))
#define LIST_FORBACK_ELEMENT(p,L,T,F) for(p=LIST_LAST_ELEMENT(L,T,F);p;p=LIST_PREV_ELEMENT(p,T,F))
/* check for emptyness */
#define LIST_EMPTY(L) (!(L)->l_size)
/* list insertion/append */
#define __LIST_COMMON_INSERT(L,N,fst,lst,nxt,prv) do{ \
(N)->nxt = (L)->fst; \
(N)->prv = 0; \
if ((L)->fst) \
(L)->fst->prv=(N); \
else \
(L)->lst=(N); \
(L)->fst=(N); \
(L)->l_size++; \
}while(0)
#define LIST_INSERT(L,N) __LIST_COMMON_INSERT(L,N,l_first,l_last,n_next,n_prev)
#define LIST_APPEND(L,N) __LIST_COMMON_INSERT(L,N,l_last,l_first,n_prev,n_next)
/* node unlink */
#define __LIST_COMMON_UNLINK(L,N,lst,nxt,prv) \
if ((N)->nxt) (N)->nxt->prv = (N)->prv; \
else { \
if((L)->lst != (N)) break; \
(L)->lst = (N)->prv; \
}
#define LIST_UNLINK(L,N) do{ \
if (!(L)->l_size) break; \
__LIST_COMMON_UNLINK(L,N,l_last,n_next,n_prev); \
__LIST_COMMON_UNLINK(L,N,l_first,n_prev,n_next);\
(L)->l_size--; \
(N)->n_next = (N)->n_prev = 0; \
} while(0)
/* same for elements, you provide the list reference, Element reference, type of elements, (F)ield name of the list nodes in T */
#define LIST_INSERT_ELEMENT(L,E,T,F) LIST_INSERT(L,LIST_NODE(E,F))
#define LIST_APPEND_ELEMENT(L,E,T,F) LIST_APPEND(L,LIST_NODE(E,F))
#define LIST_UNLINK_ELEMENT(L,E,T,F) LIST_UNLINK(L,LIST_NODE(E,F))
#endif /* LISTS_H */
这个模块的使用(只是一个头文件)如下所示:
/* Standard include files */
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include "lists.h"
/* type of elements we are double linking. */
struct nodo {
int num;
LNODE_T node; /* list nodes, just two pointers */
};
LIST_DECLARE(lista_nodos); /* declaration and initialization */
/* adding a node */
struct nodo *add(int num) {
struct nodo *n = malloc(sizeof *n); /* get a node, you don't need to malloc, it can be a global. */
n->num = num;
LIST_APPEND_ELEMENT(&lista_nodos, n, struct nodo, node);
return n;
}
void list(){
struct nodo *n;
printf("size=%d: ", lista_nodos.l_size);
/* foreach loop, n is the iterator, and you must specify the type and the field in the type that has the pointers. */
LIST_FOREACH_ELEMENT(n, &lista_nodos, struct nodo, node) {
printf("<%d>", n->num);
}
printf(";\n");
}
int main (int argc, char **argv)
{
struct nodo *n;
add(1); list();
add(2); list();
add(3); list();
while(n = LIST_FIRST_ELEMENT(&lista_nodos, struct nodo, node)) {
LIST_UNLINK_ELEMENT(&lista_nodos, n, struct nodo, node);
list();
}
add(4);
list();
n = add(5);
list();
add(6);
list();
LIST_UNLINK_ELEMENT(&lista_nodos, n, struct nodo, node); list();
while(n = LIST_LAST_ELEMENT(&lista_nodos, struct nodo, node)) {
LIST_UNLINK_ELEMENT(&lista_nodos, n, struct nodo, node);
list();
}
} /* main */
如果您想下载此代码,it is stored in my repository in github。您可以免费下载和使用它,它的版权归我所有,并且可以在 BSD 许可下使用。