Linux内核链表学习笔记
2016-06-20 10:36
435 查看
内核的链表一般都是双向循环链表,双向循环链表的效率是最高的,找头节点,尾节点,直接前驱,直接后继时间复杂度都是O(1),而使用单链表,单向循环链表或其他形式的链表是不能完成的。
链表的数据结构,定义在includ/linux/list.h下
定义一个带数据域的数据类型mystruct
一、初始化
1.宏:
2.函数
定义两个mystruct型变量 first, second 并分别用两种方法初始化它们的指针:
现在需要一个变量以代表链表的表头,使用LIST_HEAD宏将其初始化为空表
二、插入
list_add是如下定义的函数
内部函数__list_add:
三、遍历
1.遍历宏
2.由成员变量地址求结构体类型的地址
我们有地址struct list_head域的地址,但是没有包含它的结构体类型(暂时叫他目标类型)的地址,使用list_entry宏获得目标类型的地址
type结构体类型(mystruct类型,目标类型)
member成员变量(mylist)
遍历:
struct list_head *position=NULL;
struct mystruct *datastructureptr=NULL;
list_for_each(position,mylinkedlist){
datastructureptr=list_entry(position,struct mystruct,mylist);
printk("data=%d/n",datastructureptr->data);
}
更方便的一个宏
链表的数据结构,定义在includ/linux/list.h下
struct list_head { struct list_head *next, *prev; };
定义一个带数据域的数据类型mystruct
struct mystruct { int data ; struct list_head mylist ; } ;
一、初始化
1.宏:
#define LIST_HEAD_INIT(name){&(name), &(name)}
2.函数
<span style="font-family:SimSun;font-size:18px;"><strong>static inline void INIT_LIST_HEAD(struct list_head *list){ <span style="white-space:pre"> </span>list->next=list; <span style="white-space:pre"> </span>list->prev=list; }</strong></span>
定义两个mystruct型变量 first, second 并分别用两种方法初始化它们的指针:
<span style="font-family:SimSun;font-size:18px;"><strong>struct mystruct first ={ .data=10, .mylist=LIST_HEAD_INIT(first.mylist) }; struct mystruct second; second.data=20; INIT_LIST_HEAD(&second.mylist);</strong></span>
现在需要一个变量以代表链表的表头,使用LIST_HEAD宏将其初始化为空表
<strong><span style="font-family:SimSun;font-size:18px;">#define LIST_HEAD(name) struct list_head name=LIST_HEAD_INIT(name)</span></strong>LIST_HEAD(mylinkedlist);
二、插入
<strong><span style="font-family:SimSun;font-size:18px;">list_add ( &first.mylist , &mylinkedlist ) ; list_add ( &second.mylist , &mylinkedlist ) ;</span></strong>
list_add是如下定义的函数
<strong><span style="font-family:SimSun;font-size:18px;">static inline void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } </span></strong>
内部函数__list_add:
<strong><span style="font-family:SimSun;font-size:18px;"> static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } </span></strong>
三、遍历
1.遍历宏
#define list_for_each(pos,head) \ for (pos=(head)->next;pos!=(head);pos=pos->next)
2.由成员变量地址求结构体类型的地址
我们有地址struct list_head域的地址,但是没有包含它的结构体类型(暂时叫他目标类型)的地址,使用list_entry宏获得目标类型的地址
#define list_entry(ptr, type, member) container_of(ptr, type, member)ptr 成员变量指针(list_head指针)
type结构体类型(mystruct类型,目标类型)
member成员变量(mylist)
container_of宏定义在[include/linux/kernel.h]中: #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) offsetof宏定义在[include/linux/stddef.h]中: #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
遍历:
struct list_head *position=NULL;
struct mystruct *datastructureptr=NULL;
list_for_each(position,mylinkedlist){
datastructureptr=list_entry(position,struct mystruct,mylist);
printk("data=%d/n",datastructureptr->data);
}
更方便的一个宏
418 #define list_for_each_entry(pos, head, member) \ 419 for (pos = list_entry((head)->next, typeof(*pos), member); \ 420 &pos->member != (head); \ 421 pos = list_entry(pos->member.next, typeof(*pos), member)) 422
相关文章推荐
- linux下的struct sigaction
- 浅析Linux下的堆内存管理
- linux简单命令
- 嵌入式Linux系统启动过程
- LINUX常用命令
- 树莓派上基于图形界面的安装程序-synaptic
- 安装交叉编译器后,无法执行arm-linux-gcc -v
- Linux下修改文件创建时间(修改文件更改时间)
- linux内核部件分析之——设备驱动模型之class
- Linux内核日志开关
- Linux操作系统的权限代码分析【转】
- Linux 指令
- (转)资源监控工具Spotlight监测LINUX
- 使用screen将程序放到背景运行
- VMware虚拟机的安装
- 嵌入式 Linux C语言(十三)——双链表
- 嵌入式 Linux C语言(十二)——单链表
- linux 查看磁盘空间大小
- Linux下的文件查找命令——find
- Linux Server(一)搭建Java、PHP生产环境