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:
#ifndef _INIT_LIST_H_
#define _INIT_LIST_H_ #ifndef offsetof
/* Offset of member MEMBER in a struct of type TYPE. */
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif struct listnode
{
struct listnode *next;
struct listnode *prev;
}; #define node_to_item(node, container, member) \
(container *) (((char*) (node)) - offsetof(container, member)) #define list_declare(name) \
struct listnode name = { \
.next = &name, \
.prev = &name, \
} #define list_for_each(node, list) \
for (node = (list)->next; node != (list); node = node->next) #define list_for_each_reverse(node, list) \
for (node = (list)->prev; node != (list); node = node->prev) void list_init(struct listnode *list);
void list_add_tail(struct listnode *list, struct listnode *item);
void list_remove(struct listnode *item); #define list_empty(list) ((list) == (list)->next)
#define list_head(list) ((list)->next)
#define list_tail(list) ((list)->prev) #endif
list.h
#ifndef _INIT_LIST_H_
#define _INIT_LIST_H_ #ifndef offsetof
/* Offset of member MEMBER in a struct of type TYPE. */
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif struct listnode
{
struct listnode *next;
struct listnode *prev;
}; #define node_to_item(node, container, member) \
(container *) (((char*) (node)) - offsetof(container, member)) #define list_declare(name) \
struct listnode name = { \
.next = &name, \
.prev = &name, \
} #define list_for_each(node, list) \
for (node = (list)->next; node != (list); node = node->next) #define list_for_each_reverse(node, list) \
for (node = (list)->prev; node != (list); node = node->prev) void list_init(struct listnode *list);
void list_add_tail(struct listnode *list, struct listnode *item);
void list_remove(struct listnode *item); #define list_empty(list) ((list) == (list)->next)
#define list_head(list) ((list)->next)
#define list_tail(list) ((list)->prev) #endif
list.c:
#include "list.h" void list_init(struct listnode *node)
{
node->next = node;
node->prev = node;
} void list_add_tail(struct listnode *head, struct listnode *item)
{
item->next = head;
item->prev = head->prev;
head->prev->next = item;
head->prev = item;
} void list_remove(struct listnode *item)
{
item->next->prev = item->prev;
item->prev->next = item->next;
}
list.c
#include "list.h" void list_init(struct listnode *node)
{
node->next = node;
node->prev = node;
} void list_add_tail(struct listnode *head, struct listnode *item)
{
item->next = head;
item->prev = head->prev;
head->prev->next = item;
head->prev = item;
} void list_remove(struct listnode *item)
{
item->next->prev = item->prev;
item->prev->next = item->next;
}
测试代码list_test.c:
#include<stdio.h>
#include<stdlib.h>
#include "list.h" #define STUDENT_FREE_MEMORY //声明链表节点
typedef struct {
int id;
char *name;
struct listnode _list;
}student; //遍历函数指针
typedef void (*student_foreach_fun)(student *stu,void *data); //声明链表
static list_declare(student_list); //添加节点
int student_add(struct listnode *list,student *stu)
{
list_init(&stu->_list);
list_add_tail(list,&stu->_list);
return ;
} //删除节点,释放节点空间
int student_del(struct listnode *list,int id)
{
struct listnode *node;
student *stu;
list_for_each(node,list){
stu = node_to_item(node,student,_list);
if(id == stu->id){
printf("list_del, id:%d,name:%s\n",stu->id,stu->name);
list_remove(node);
#ifdef STUDENT_FREE_MEMORY
//释放节点空间
free(stu);
stu = NULL;
#endif
return ; } } return ;
} //节点遍历
void student_foreach(struct listnode *list,student_foreach_fun fun,void *data)
{
struct listnode *node;
student *stu;
list_for_each(node,list){
stu = node_to_item(node,student,_list);
fun(stu,data);
} } //打印节点信息
void student_print(student *stu,void *data)
{
printf("id:%d,name:%s\n",stu->id,stu->name);
} int main()
{
int i,len;
student *stu;
char *stu_name[]={"tonny","andy","michael","leslie","john"}; len = sizeof(stu_name)/sizeof(stu_name[]);
//添加节点
for(i=;i<len;i++){
stu = calloc(,sizeof(student));
stu->id = i + ;
stu->name = stu_name[i]; student_add(&student_list,stu);
} //打印所有节点
student_foreach(&student_list,student_print,(void *)); //删除节点
student_del(&student_list,);
student_foreach(&student_list,student_print,(void *)); //删除节点
student_del(&student_list,);
student_foreach(&student_list,student_print,(void *)); return ; }
list_test.c
#include<stdio.h>
#include<stdlib.h>
#include "list.h" #define STUDENT_FREE_MEMORY //声明链表节点
typedef struct {
int id;
char *name;
struct listnode _list;
}student; //遍历函数指针
typedef void (*student_foreach_fun)(student *stu,void *data); //声明链表
static list_declare(student_list); //添加节点
int student_add(struct listnode *list,student *stu)
{
list_init(&stu->_list);
list_add_tail(list,&stu->_list);
return ;
} //删除节点,释放节点空间
int student_del(struct listnode *list,int id)
{
struct listnode *node;
student *stu;
list_for_each(node,list){
stu = node_to_item(node,student,_list);
if(id == stu->id){
printf("list_del, id:%d,name:%s\n",stu->id,stu->name);
list_remove(node);
#ifdef STUDENT_FREE_MEMORY
//释放节点空间
free(stu);
stu = NULL;
#endif
return ; } } return ;
} //节点遍历
void student_foreach(struct listnode *list,student_foreach_fun fun,void *data)
{
struct listnode *node;
student *stu;
list_for_each(node,list){
stu = node_to_item(node,student,_list);
fun(stu,data);
} } //打印节点信息
void student_print(student *stu,void *data)
{
printf("id:%d,name:%s\n",stu->id,stu->name);
} int main()
{
int i,len;
student *stu;
char *stu_name[]={"tonny","andy","michael","leslie","john"}; len = sizeof(stu_name)/sizeof(stu_name[]);
//添加节点
for(i=;i<len;i++){
stu = calloc(,sizeof(student));
stu->id = i + ;
stu->name = stu_name[i]; student_add(&student_list,stu);
} //打印所有节点
student_foreach(&student_list,student_print,(void *)); //删除节点
student_del(&student_list,);
student_foreach(&student_list,student_print,(void *)); //删除节点
student_del(&student_list,);
student_foreach(&student_list,student_print,(void *)); return ; }
Makefile:
TARGET=list_test
SRC=list_test.c list.c
#SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
CFLAGS=-g -Wall -o $(TARGET):$(SRC)
gcc $(SRC) $(CFLAGS) $(TARGET)
clean:
rm $(OBJ) $(TARGET)
Makefile
TARGET=list_test
SRC=list_test.c list.c
#SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
CFLAGS=-g -Wall -o $(TARGET):$(SRC)
gcc $(SRC) $(CFLAGS) $(TARGET)
clean:
rm $(OBJ) $(TARGET)
linux内核链表使用的更多相关文章
- C语言 Linux内核链表(企业级链表)
//Linux内核链表(企业级链表) #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> ...
- 深入分析 Linux 内核链表--转
引用地址:http://www.ibm.com/developerworks/cn/linux/kernel/l-chain/index.html 一. 链表数据结构简介 链表是一种常用的组织有序数据 ...
- Linux 内核链表
一 . Linux内核链表 1 . 内核链表函数 1.INIT_LIST_HEAD:创建链表 2.list_add:在链表头插入节点 3.list_add_tail:在链表尾插入节点 4.list_d ...
- linux内核链表分析
一.常用的链表和内核链表的区别 1.1 常规链表结构 通常链表数据结构至少应包含两个域:数据域和指针域,数据域用于存储数据,指针域用于建立与下一个节点的联系.按照指针域的组织以及各个节 ...
- 深入分析 Linux 内核链表
转载:http://www.ibm.com/developerworks/cn/linux/kernel/l-chain/ 一. 链表数据结构简介 链表是一种常用的组织有序数据的数据结构,它通过指 ...
- Linux 内核 链表 的简单模拟(2)
接上一篇Linux 内核 链表 的简单模拟(1) 第五章:Linux内核链表的遍历 /** * list_for_each - iterate over a list * @pos: the & ...
- Linux 内核 链表 的简单模拟(1)
第零章:扯扯淡 出一个有意思的题目:用一个宏定义FIND求一个结构体struct里某个变量相对struc的编移量,如 struct student { int a; //FIND(struct stu ...
- linux内核链表的移植与使用
一. Linux内核链表为双向循环链表,和数据结构中所学链表类似,具体不再细讲.由于在内核中所实现的函数十分经典,所以移植出来方便后期应用程序中的使用. /********************* ...
- [国嵌攻略][108][Linux内核链表]
链表简介 链表是一种常见的数据结构,它通过指针将一系列数据节点连接成一条数据链.相对于数组,链表具有更好的动态性,建立链表时无需预先知道数据总量,可以随机分配空间,可以高效地在链表中的任意位置实时插入 ...
- linux内核链表的使用
linux内核链表:链表通常包括两个域:数据域和指针域.struct list_head{struct list_head *next,*prev;};include/linux/list.h中实现了 ...
随机推荐
- 编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串'welcome to masm!'
80*25彩色字符模式显示缓冲区的结构: 内存地址空间中,B8000H~BFFFFH共32KB的空间,为80*25彩色字符模式的显示缓冲区.向这个地址空间写入数据,写入的内容将立即出现在显示器上. 在 ...
- JFinal Web开发学习(三)前后台路由设计
效果图: 一.写控制器 1.在controller包中新建AdminController后台控制器,继承Controller,实现一个index方法,作为的处理方法. /admin 后面,这个控制器中 ...
- SQL truncate 、delete与drop区别[z]
[z]https://www.cnblogs.com/8765h/archive/2011/11/25/2374167.html 相同点: 1.truncate和不带where子句的delete.以及 ...
- [z]一分钟教你知道乐观锁和悲观锁的区别
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁.传统的关系型数据 ...
- PAT 1039 到底买不买(20)(20 分)
1039 到底买不买(20)(20 分) 小红想买些珠子做一串自己喜欢的珠串.卖珠子的摊主有很多串五颜六色的珠串,但是不肯把任何一串拆散了卖.于是小红要你帮忙判断一下,某串珠子里是否包含了全部自己想要 ...
- VS“当前上下文中不存在名称“ViewBag”,当前上下文不存在名称“model””-已解决
自己的项目出现了错误提示,却能编译成功,但是有点强迫症,总是想解决这个错误. 上网找了一堆,都是删除缓存等一些方法,但是没有多大用处,我觉得还是版本号不对,没有引用进来相应的配置,所以配置下了Conf ...
- How to Set Ckeditor ReadOnly Mode
CKEditor API makes it possible to render the editor content read-only (and thus impossible for the u ...
- Netty 源码(一)Netty 组件简介
Netty 源码(一)Netty 组件简介 Netty 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) 一.Netty 架构 Core: ...
- java 23种设计模式学习。
一.3大类设计模式:创建型,结构型,行为型. a.5种创建型模式:工厂方法,抽象工厂,单例,建造者,原型. b.7种结构型模式:适配器,装饰器,代理,外观,桥接,组合,享元. c.11种行为型模式:策 ...
- vue 浏览器页面刷新时执行一段代码
当刷新(浏览器刷新)页面的时候,重置到首页(或其他页面)纯js的是window.onload()但是vue几乎不会用到这个,vue所有的是生命周期那么我们可以根据生命周期来实现这个beforeCrea ...