首页 > 代码库 > 侵入式单链表的简单实现
侵入式单链表的简单实现
通常情况下,单链表的定义是这样子滴,
typedef struct foo_s { int data; struct foo_s *next; } foo_t;
结构体里包含了链表指针next; 而侵入式单链表却不同,让结构体包含一个通用的链表。看起来是这个样儿滴,
typedef struct list_s { struct list_s *next; } list_t; typedef struct foo_s { int data; list_t link; } foo_t;
所有包含了list_t link的结点构成一个单链表。前一节我们详细分析了offsetof, typeof和container_of, 下面给出一个最简单的侵入式单链表实现。
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 /** 16 * container_of - cast a member of a structure out to the containing structure 17 * @ptr: the pointer to the member. 18 * @type: the type of the container struct this is embedded in. 19 * @member: the name of the member within the struct. 20 * 21 */ 22 #define container_of(ptr, type, member) ({ 23 const typeof( ((type *)0)->member ) *__mptr = (ptr); 24 (type *)( (char *)__mptr - offsetof(type, member) );}) 25 26 typedef struct list_s { 27 struct list_s *next; 28 } list_t; 29 30 typedef void (*list_handler_t)(void *arg); 31 32 extern void list_init(list_t **head, list_t *node); 33 extern void list_fini(list_t *head, list_handler_t fini); 34 extern void list_show(list_t *head, list_handler_t show); 35 36 #ifdef __cplusplus 37 } 38 #endif 39 40 #endif /* _LIST_H */
2. list.c
1 /* 2 * Generic single linked list implementation 3 */ 4 #include <stdio.h> 5 #include "list.h" 6 7 void 8 list_init(list_t **head, list_t *node) 9 { 10 static list_t *tail = NULL; 11 12 if (*head == NULL) { 13 *head = tail = node; 14 return; 15 } 16 17 tail->next = node; 18 tail = node; 19 node->next = NULL; 20 } 21 22 void 23 list_show(list_t *head, list_handler_t show) 24 { 25 for (list_t *p = head; p != NULL; p = p->next) 26 show(p); 27 } 28 29 void 30 list_fini(list_t *head, list_handler_t fini) 31 { 32 list_t *p = head; 33 while (p != NULL) { 34 list_t *q = p; 35 p = p->next; 36 fini(q); 37 } 38 }
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_show(void *arg) 12 { 13 list_t *q = (list_t *)arg; 14 foo_t *p = container_of(q, foo_t, link); 15 16 printf("show (list) %p next (list) %p \t: " 17 "show (node) %p = {0x%x, %p}\n", 18 q, p->link.next, p, p->data, p->link.next); 19 } 20 21 static void 22 foo_fini(void *arg) 23 { 24 list_t *q = (list_t *)arg; 25 foo_t *p = container_of(q, foo_t, link); 26 27 foo_t *next_nodep = NULL; 28 if (p->link.next != NULL) 29 next_nodep = container_of(p->link.next, foo_t, link); 30 31 printf("free (node) %p next (node) %p\n", p, next_nodep); 32 p->link.next = NULL; 33 free(p); 34 } 35 36 int 37 main(int argc, char *argv[]) 38 { 39 if (argc != 2) { 40 fprintf(stderr, "Usage: %s <num>\n", argv[0]); 41 return -1; 42 } 43 44 list_t *head = NULL; 45 for (int i = 0; i < atoi(argv[1]); i++) { 46 foo_t *p = (foo_t *)malloc(sizeof (foo_t)); 47 if (p == NULL) /* error */ 48 return -1; 49 p->data = http://www.mamicode.com/0x1001 + i; 50 51 printf("init (node) %p\n", p); 52 list_init(&head, &p->link); 53 } 54 55 list_show(head, foo_show); 56 57 list_fini(head, foo_fini); 58 59 return 0; 60 }
4. Makefile
CC = gcc CFLAGS = -g -Wall -m32 -std=gnu99 all: foo foo: foo.o list.o ${CC} ${CFLAGS} -o $@ $^ foo.o: foo.c ${CC} ${CFLAGS} -c $< list.o: list.c list.h ${CC} ${CFLAGS} -c $< clean: rm -f *.o clobber: clean rm -f foo 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) 0x88a1008 init (node) 0x88a1018 init (node) 0x88a1028 show (list) 0x88a100c next (list) 0x88a101c : show (node) 0x88a1008 = {0x1001, 0x88a101c} show (list) 0x88a101c next (list) 0x88a102c : show (node) 0x88a1018 = {0x1002, 0x88a102c} show (list) 0x88a102c next (list) (nil) : show (node) 0x88a1028 = {0x1003, (nil)} free (node) 0x88a1008 next (node) 0x88a1018 free (node) 0x88a1018 next (node) 0x88a1028 free (node) 0x88a1028 next (node) (nil)
小结: 在类型为foo_t的结构体中包含了成员变量list_t link, 那么根据link.next的值(本质上是内存地址)就能使用container_of()计算出结构体变量的内存首地址。一旦拿到了结构体变量的内存首地址,访问其内容就易如反掌。
侵入式单链表的简单实现
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。