linux内核链表使用

原文链接:http://blog.csdn.net/xnwyd/article/details/7359373

Linux内核链表的核心思想是:在用户自定义的结构A中声明list_head类型的成员p,这样每个结构类型为A的变量a中,都拥有同样的成员p,如下:

struct A{

int property;

struct list_head p;

}

其中,list_head结构类型定义如下:

struct list_head {

struct list_head *next,*prev;

};

list_head拥有两个指针成员,其类型都为list_head,分别为前驱指针prev和后驱指针next。

假设:

(1)多个结构类型为A的变量a1...an,其list_head结构类型的成员为p1...pn

(2)一个list_head结构类型的变量head,代表头节点

使:

(1)head.next= p1 ; head.prev = pn

(2) p1.prev = head,p1.next = p2;

(3)p2.prev= p1 , p2.next = p3;

(n)pn.prev= pn-1 , pn.next = head

以上,则构成了一个循环链表。

因p是嵌入到a中的,p与a的地址偏移量可知,又因为head的地址可知,所以每个结构类型为A的链表节点a1...an的地址也是可以计算出的,从而可实现链表的遍历,在此基础上,则可以实现链表的各种操作。

下面是从linux内核中移植出来的简单链表,list.h和list.c:

list.h:

 1 #ifndef _INIT_LIST_H_
 2 #define _INIT_LIST_H_
 3
 4 #ifndef offsetof
 5 /* Offset of member MEMBER in a struct of type TYPE. */
 6 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 7 #endif
 8
 9 struct listnode
10 {
11     struct listnode *next;
12     struct listnode *prev;
13 };
14
15 #define node_to_item(node, container, member) 16     (container *) (((char*) (node)) - offsetof(container, member))
17
18 #define list_declare(name) 19     struct listnode name = { 20         .next = &name, 21         .prev = &name, 22     }
23
24 #define list_for_each(node, list) 25     for (node = (list)->next; node != (list); node = node->next)
26
27 #define list_for_each_reverse(node, list) 28     for (node = (list)->prev; node != (list); node = node->prev)
29
30 void list_init(struct listnode *list);
31 void list_add_tail(struct listnode *list, struct listnode *item);
32 void list_remove(struct listnode *item);
33
34 #define list_empty(list) ((list) == (list)->next)
35 #define list_head(list) ((list)->next)
36 #define list_tail(list) ((list)->prev)
37
38 #endif

list.c:

 1 #include "list.h"
 2
 3 void list_init(struct listnode *node)
 4 {
 5     node->next = node;
 6     node->prev = node;
 7 }
 8
 9 void list_add_tail(struct listnode *head, struct listnode *item)
10 {
11     item->next = head;
12     item->prev = head->prev;
13     head->prev->next = item;
14     head->prev = item;
15 }
16
17 void list_remove(struct listnode *item)
18 {
19     item->next->prev = item->prev;
20     item->prev->next = item->next;
21 }

测试代码list_test.c:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include "list.h"
  4
  5 #define STUDENT_FREE_MEMORY
  6
  7 //声明链表节点
  8 typedef struct {
  9     int id;
 10     char *name;
 11     struct listnode _list;
 12 }student;
 13
 14 //遍历函数指针
 15 typedef void (*student_foreach_fun)(student *stu,void *data);
 16
 17
 18 //声明链表
 19 static list_declare(student_list);
 20
 21 //添加节点
 22 int student_add(struct listnode *list,student *stu)
 23 {
 24     list_init(&stu->_list);
 25     list_add_tail(list,&stu->_list);
 26     return 0;
 27 }
 28
 29 //删除节点,释放节点空间
 30 int student_del(struct listnode *list,int id)
 31 {
 32     struct listnode *node;
 33     student *stu;
 34     list_for_each(node,list){
 35         stu = node_to_item(node,student,_list);
 36         if(id == stu->id){
 37             printf("list_del, id:%d,name:%s\n",stu->id,stu->name);
 38             list_remove(node);
 39 #ifdef STUDENT_FREE_MEMORY
 40             //释放节点空间
 41             free(stu);
 42             stu = NULL;
 43 #endif
 44             return 1;
 45
 46         }
 47
 48     }
 49
 50     return 0;
 51 }
 52
 53 //节点遍历
 54 void student_foreach(struct listnode *list,student_foreach_fun fun,void *data)
 55 {
 56     struct listnode *node;
 57     student *stu;
 58     list_for_each(node,list){
 59         stu = node_to_item(node,student,_list);
 60         fun(stu,data);
 61     }
 62
 63 }
 64
 65 //打印节点信息
 66 void student_print(student *stu,void *data)
 67 {
 68     printf("id:%d,name:%s\n",stu->id,stu->name);
 69 }
 70
 71 int main()
 72 {
 73     int i,len;
 74     student *stu;
 75     char *stu_name[]={"tonny","andy","michael","leslie","john"};
 76
 77
 78     len = sizeof(stu_name)/sizeof(stu_name[0]);
 79     //添加节点
 80     for(i=0;i<len;i++){
 81         stu = calloc(1,sizeof(student));
 82         stu->id = i + 1;
 83         stu->name = stu_name[i];
 84
 85         student_add(&student_list,stu);
 86     }
 87
 88     //打印所有节点
 89     student_foreach(&student_list,student_print,(void *)0);
 90
 91     //删除节点
 92     student_del(&student_list,1);
 93     student_foreach(&student_list,student_print,(void *)0);
 94
 95     //删除节点
 96     student_del(&student_list,5);
 97     student_foreach(&student_list,student_print,(void *)0);
 98
 99     return 0;
100
101
102 }

Makefile:

 1 TARGET=list_test
 2 SRC=list_test.c list.c
 3 #SRC=$(wildcard *.c)
 4 OBJ=$(SRC:.c=.o)
 5 CFLAGS=-g -Wall -o
 6
 7 $(TARGET):$(SRC)
 8     gcc $(SRC) $(CFLAGS) $(TARGET)
 9 clean:
10     rm $(OBJ) $(TARGET) 
时间: 2024-10-15 23:49:02

linux内核链表使用的相关文章

Linux 内核链表

一 . Linux内核链表 1 . 内核链表函数 1.INIT_LIST_HEAD:创建链表 2.list_add:在链表头插入节点 3.list_add_tail:在链表尾插入节点 4.list_del:删除节点 5.list_entry:取出节点 6.list_for_each:遍历链表 2.程序代码

例说Linux内核链表(二)

链表使用 我认为熟悉内核链表功能最好的方法就是看一些简单的实例,实例是一个非常好的素材去更好的理解链表. 下面是一个例子,包含创建,添加,删除和遍历链表. <span style="font-size:14px;"><span style="color:#330099;">#include <stdio.h> #include <stdlib.h> #include "list.h" struct

Linux 内核 链表 的简单模拟(2)

接上一篇Linux 内核 链表 的简单模拟(1) 第五章:Linux内核链表的遍历 /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each(pos, head) for (pos = (head)->next; pos != (head);

例说Linux内核链表(一)

介绍 众所周知,Linux内核大部分是使用GNU C语言写的.C不同于其他的语言,它不具备一个好的数据结构对象或者标准对象库的支持.所以可以借用Linux内核源码树的循环双链表是一件很值得让人高兴的事. 在include/linux/list.h文件中用C实现了一个好用的循环链表.它是有效而且易于操作的,否则它也不会被内核使用(译者注:在kernel中大量的使用了循环双链表结构,比如在在进程描述符实体中我们就可以看到很多struct list_head的身影).不管何时,依靠这种结构,在内核中都

例说Linux内核链表(三)

经常使用的linux内核双向链表API介绍 linux link list结构图例如以下: 内核双向链表的在linux内核中的位置:/include/linux/list.h 使用双向链表的过程,主要过程包括创建包括struct link_head结构的结构体(item),建立链表头.向链表中加入item(自己定义数据结构.双向链表数据单元).删除链表节点.遍历链表,判空等. 1.建立自己定义链表数据结构 struct kool_list{ int to; struct list_head li

linux内核链表的使用

linux内核链表:链表通常包括两个域:数据域和指针域.struct list_head{struct list_head *next,*prev;};include/linux/list.h中实现了一套精彩的链表数据结构.传统的链表指针指向下一个节点的头部.linux链表指针指向下一个指针list_head结构(*next),双向循环.不会随着外部数据的变化而变化,使它具有通用性.? -------------------------------------------------------

linux内核链表的移植与使用

一.  Linux内核链表为双向循环链表,和数据结构中所学链表类似,具体不再细讲.由于在内核中所实现的函数十分经典,所以移植出来方便后期应用程序中的使用. /*********************************** 文件名:kernel link list of linux.h 作者:Bumble Bee 日期:2015-1-31 功能:移植linux内核链表 ************************************/ /*链表结点数据结构*/ struct lis

Linux 内核链表使用举例

链表数据结构的定义很简洁: struct list_head { struct list_head *next, *prev; }; list_head结构包含两个指向list_head结构的指针prev和next,该内核链表具备双链表功能,通常它都组织成双循环链表,这里的list_head没有数据域.在Linux内核链表中,不是在链表结构中包含数据,而是在数据结构中包含链表节点.下面是一个简单的内核模块的例子,包含了对链表进行插入.删除.遍历的一些函数: list.c: #include <l

链表的艺术——Linux内核链表分析

引言: 链表是数据结构中的重要成员之中的一个.因为其结构简单且动态插入.删除节点用时少的长处,链表在开发中的应用场景许多.仅次于数组(越简单应用越广). 可是.正如其长处一样,链表的缺点也是显而易见的.这里当然不是指随机存取那些东西,而是因为链表的构造方法(在一个结构体中套入其同类型指针)使得链表本身的逻辑操作(如添加结点,删除结点,查询结点等),往往与其应用场景中的业务数据相互混杂.这导致我们每次使用链表都要进行手工打造,做过链表的人肯定对此深有了解. 是否能将链表从变换莫測的业务数据中抽象出