侵入式单链表的简单实现(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 = 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

侵入式单链表的简单实现(cont)的相关文章

侵入式单链表的简单实现

通常情况下,单链表的定义是这样子滴, 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; 所有包含了l

c# 单链表实现 简单示例(可复制直接运行)

最近学习数据结构,发现c# 其实和c 的链表的实现差不多的 下面是一段可直接运行的代码 1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Threading; 5 6 namespace SingleLinkedList 7 { 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 13 //实例调用

单链表的简单操作

单链表是一种最简单的线性表的链式存储结构,单链表又称线性链表,每个数据元素用一个结点来存储,结点分为存放数据元素的data和存放指向链表下一个结点的指针next. 链表实现:(LinkList.h) //单链表 #ifndef LINKLIST_H_ #define LINKLIST_H_ #include <iostream> //using namespace std; template <typename T> struct Node { //数据成员 T data; Nod

单链表的简单c++实现

以下代码只实现了单链表的手动创建以及输出功能 #include<iostream> using namespace std; struct node { int data; node *next; }; class list { public: void creat(); void show(); private: node *head; }; void list::creat() //创建链表 { node *f=new node(); //建立链表的第一个元素 f->data=44;

对带头结点的单链表的简单操作

#pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h> #include<memory.h> #define DataType int           //int 可以改写为其它数据类型 typedef struct Node { DataType data; struct Node *next; }Node,*pNode;          //定义结点结构体      

一次单链表的简单练习

#include "stdio.h"#include <stdlib.h>//#include "string.h" typedef int elemType ; typedef struct Node{ /* 定义单链表结点类型 */ elemType element; Node *next;}Node; /* 1.初始化线性表,即置单链表的表头指针为空 */void initList(Node *pNode){ pNode = NULL; print

单链表的简单实现

//定义一个节点类 class Node{ int data; Node nextNode; public Node(int data) { // TODO Auto-generated constructor stub this.data = data; } } 链表类: package test; /** * * @author dao * */ // 链表类 public class ListNode { Node firstNode; // 第一个节点 int length = 0; N

2-5-归并链式存储的单链表-线性表-第2章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第2章  线性表 - 归并单链表(链式存储) ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? SinglyLinkedList.c        相关测试数据下载

C++侵入式链表

C++标准模板库中的list是非侵入式的链表,当我们通过对象来删除容器中的对象时,需要从头到尾查找一次得到iterator,最后通过iterator来删除对象.这样删除容器中的对象时比较缓慢,所以就实现了一个侵入式链表. intrusive_list.h #ifndef _Intrusive_List_H_ #define _Intrusive_List_H_ // 侵入式链表 template<class T> class intrusive_list { public: struct No