前一节介绍的侵入式链表的实现的封装性做得不好,因为会让消费者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 [email protected] $^ 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
时间: 2024-10-25 20:16:56