首页 > 代码库 > 侵入式单链表的简单实现(cont)

侵入式单链表的简单实现(cont)

前一节介绍的侵入式链表的实现的封装性做得不好,因为会让消费者foo.c直接使用宏container_of()。这一节对list的定义做了一下改进,如下所示:

typedef struct list_s {
        struct list_s *next;
        size_t offset;
} list_t;

既然链表结点存了offset, 那么就不再需要container_of()了。(注:Solaris的侵入式双向循环链表就是这么实现的)

1. list.h

 1 #ifndef _LIST_H
 2 #define _LIST_H
 3 
 4 #ifdef  __cplusplus
 5 extern "C" {
 6 #endif
 7 
 8 /**
 9  * offsetof - offset of a structure member
10  * @TYPE:       the type of the struct.
11  * @MEMBER:     the name of the member within the struct.
12  */
13 #define offsetof(TYPE, MEMBER) ((size_t)(&(((TYPE *)0)->MEMBER)))
14 
15 typedef struct list_s {
16         struct list_s *next;
17         size_t offset;
18 } list_t;
19 
20 extern list_t *list_d2l(void *object, size_t offset);
21 extern   void *list_head(list_t *list);
22 extern   void *list_next(list_t *list);
23 
24 #ifdef  __cplusplus
25 }
26 #endif
27 
28 #endif /* _LIST_H */

2. list.c

 1 /*
 2  * Generic single linked list implementation
 3  */
 4 #include <stdio.h>
 5 #include "list.h"
 6 
 7 list_t *
 8 list_d2l(void *object, size_t offset)
 9 {
10         if (object == NULL)
11                 return NULL;
12 
13         list_t *p = (list_t *)((char *)object + offset);
14         p->offset = offset;
15         p->next = NULL;
16 
17         return p;
18 }
19 
20 static void *
21 list_l2d(list_t *list)
22 {
23         if (list == NULL)
24                 return NULL;
25 
26         return (void *)((char *)list - list->offset);
27 }
28 
29 void *
30 list_head(list_t *list)
31 {
32         if (list == NULL)
33                return NULL;
34 
35         return list_l2d(list);
36 }
37 
38 void *
39 list_next(list_t *list)
40 {
41         if (list == NULL || list->next == NULL)
42                 return NULL;
43 
44         return list_l2d(list->next);
45 }

3. foo.c

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include "list.h"
 4 
 5 typedef struct foo_s {
 6         int     data;
 7         list_t  link;
 8 } foo_t;
 9 
10 static void
11 foo_init(list_t **head, void *object, size_t offset)
12 {
13         if (object == NULL)
14                 return;
15         list_t *node = list_d2l(object, offset);
16 
17         if (*head == NULL) {
18                 *head = node;
19                 return;
20         }
21 
22         list_t *tail = NULL;
23         for (list_t *p = *head; p != NULL; p = p->next)
24                 tail = p;
25         tail->next = node;
26 }
27 
28 static void
29 foo_fini(list_t *head)
30 {
31         list_t *p = head;
32         while (p != NULL) {
33                 list_t *q = p;
34                 p = p->next;
35 
36                 void *obj = list_head(q);
37                 printf("free (node) %p next (list) %p\n", obj, p);
38                 free(obj);
39         }
40 }
41 
42 static void
43 foo_show(list_t *head)
44 {
45         for (foo_t *p = list_head(head); p != NULL; p = list_next(&p->link)) {
46                 printf("show (list) %p next (list) %p \t: "
47                     "show (node) %p = {0x%x, {%p, %d}}\n",
48                     &p->link, p->link.next,
49                     p, p->data, p->link.next, p->link.offset);
50         }
51 }
52 
53 int
54 main(int argc, char *argv[])
55 {
56         if (argc != 2) {
57                 fprintf(stderr, "Usage: %s <num>\n", argv[0]);
58                 return -1;
59         }
60 
61         list_t *head = NULL;
62         for (int i = 0; i < atoi(argv[1]); i++) {
63                 foo_t *p = (foo_t *)malloc(sizeof (foo_t));
64                 if (p == NULL) /* error */
65                         return -1;
66                 p->data = http://www.mamicode.com/0x1001 + i;
67 
68                 printf("init (node) %p\n", p);
69                 foo_init(&head, (void *)p, offsetof(foo_t, link));
70         }
71 
72         foo_show(head);
73         foo_fini(head);
74 
75         return 0;
76 }

4. Makefile

 1 CC      = gcc
 2 CFLAGS  = -g -Wall -m32 -std=gnu99
 3 
 4 all: foo
 5 
 6 foo: foo.o list.o
 7         ${CC} ${CFLAGS} -o $@ $^
 8 
 9 foo.o: foo.c
10         ${CC} ${CFLAGS} -c $<
11 
12 list.o: list.c list.h
13         ${CC} ${CFLAGS} -c $<
14 
15 clean:
16         rm -f *.o
17 
18 clobber: clean
19         rm -f foo
20 cl: clobber

5. 编译并运行

$ make
gcc -g -Wall -m32 -std=gnu99 -c foo.c
gcc -g -Wall -m32 -std=gnu99 -c list.c
gcc -g -Wall -m32 -std=gnu99 -o foo foo.o list.o

$ ./foo 3
init (node) 0x81a8008
init (node) 0x81a8018
init (node) 0x81a8028
show (list) 0x81a800c next (list) 0x81a801c     : show (node) 0x81a8008 = {0x1001, {0x81a801c, 4}}
show (list) 0x81a801c next (list) 0x81a802c     : show (node) 0x81a8018 = {0x1002, {0x81a802c, 4}}
show (list) 0x81a802c next (list) (nil)         : show (node) 0x81a8028 = {0x1003, {(nil), 4}}
free (node) 0x81a8008 next (list) 0x81a801c
free (node) 0x81a8018 next (list) 0x81a802c
free (node) 0x81a8028 next (list) (nil)

6. 用gdb查看链表

技术分享

小结: TBD

侵入式单链表的简单实现(cont)