1. 程式人生 > >侵入式單鏈表的簡單實現(cont)

侵入式單鏈表的簡單實現(cont)

con ima -o error alt set clas eric int

前一節介紹的侵入式鏈表的實現的封裝性做得不好,因為會讓消費者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 = 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)