linux内核学习之——链表篇-ChinaUnix操作系统频道.pdf
《linux内核学习之——链表篇-ChinaUnix操作系统频道.pdf》由会员分享,可在线阅读,更多相关《linux内核学习之——链表篇-ChinaUnix操作系统频道.pdf(13页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、linux内核学习之链表篇-ChinaUnix操作系统频道http:/ 21:43:59ChinaUnix首页|论坛|博客|微博|求职|读书|培训|下载|IT采购|搜索 ChinaU 请 登录 或 注册当前位置:ChinaUnix 首页 操作系统频道 linux内核学习之链表篇linux内核学习之链表篇2008年09月11日 14:38 来源:ChinaUnix博客 作者:新华网 编辑:周荣茂 -双向循环链表-来源于:list.h 设计思想:尽可能的代码重用,化大堆的链表设计为单个链表。链 表的构造:如果需要构造某类对象的特定列表,则在其结构中定义一个类型为list_head指针的成员,通过这
2、个成员将这类对象连接起来,形成所需列表,并通过通用链表函数对其进行操作。其优点是只需编写通用链表函数,即可构造和操作不同对象的列表,而无需为每类对象的每种列表编写专用函数,实现了代码的 重用。如果想对某种类型创建链表,就把一个list_head类型的变量嵌入到该类型中,用list_head中的成员和相对应的处理函数来对链表进行遍历。如果想得到相应的结构的指针,使用list_entry可以算出来。-防止重复包含同一个头文件-#ifndef _LINUX_LIST_H#define _LINUX_LIST_H .#endif 用于防止重复包含同一个list.h头文件 -struct list_he
3、ad及初始化宏-struct list_head struct list_head*next,*prev;list_head从字面上理解,好像是头结点的意思。但从这里的代码来看却是普通结点的结构体。在后面的代码中将list_head当成普通的结点linux内核学习之链表篇-ChinaUnix操作系统频道http:/ 21:43:59来处理。-LIST_HEAD_INIT()-LIST_HEAD()-INIT_LIST_HEAD()-#define LIST_HEAD_INIT(name)&(name),&(name)#define LIST_HEAD(name)struct list_head
4、 name=LIST_HEAD_INIT(name)分析:name当为结构体struct list_head的一个结构体变量,&(name)为该结构体变量的地址。用name结构体变量的始地址将该结构体变量进行初始化。#define INIT_LIST_HEAD(ptr)do (ptr)-next=(ptr);(ptr)-prev=(ptr);while(0)1.ptr为一个结构体的指针,而name为一个结构体变量;2.ptr使用时候,当用括号,(ptr);-_list_add()-list_add()-static inline void _list_add(struct list_head*
5、new,struct list_head*prev,struct list_head*next)next-prev=new;new-next=next;new-prev=prev;prev-next=new;1.普通的在两个非空结点中插入一个结点,注意new,prev,next都不能是空值。2.即:适用于中间结点插入。首结点和尾结点则由于指针为空,不能用此函数。3.在prev指针和next指针所指向的结点之间插入new指针所指向的结点。static inline void list_add(struct list_head*new,struct list_head*head)linux内核学习
6、之链表篇-ChinaUnix操作系统频道http:/ 21:43:59 _list_add(new,head,head-next);在head和head-next两指针所指向的结点之间插入new所指向的结点。即:在head指针后面插入new所指向的结点。此函数用于在头结点后面插入结点。注意:对只有一个单个结点的链表,则head-next为空,list_add()不能用。-list_add_tail()-static inline void list_add_tail(struct list_head*new,struct list_head*head)_list_add(new,head-pr
7、ev,head);在头结点指针head所指向结点的前面插入new所指向的结点。也相当于在尾结点后面增加一个new所指向的结点。(条件是:head-prev当指向尾结点)注意:1.head-prev不能为空,即若head为头结点,其head-prev当指向一个数值,一般为指向尾结点,构成循环链表。2.对只有单个结点的头结点调用此函数则会出错。-_list_del()-list_del()-static inline void _list_del(struct list_head*prev,struct list_head*next)next-prev=prev;prev-next=next;在p
8、rev和next指针所指向的结点之间,两者互相所指。在后面会看到:prev为待删除的结点的前面一个结点,next为待删除的结点的后面一个结点。static inline void list_del(struct list_head*entry)_list_del(entry-prev,entry-next);linux内核学习之链表篇-ChinaUnix操作系统频道http:/ 21:43:59 entry-next=LIST_POISON1;entry-prev=LIST_POISON2;删除entry所指的结点,同时将entry所指向的结点指针域封死。对LIST_POISON1,LIST_
9、POISON2的解释说明:Linux 内核中解释:These are non-NULL pointers that will result in page faults under normal circumstances,used to verify that nobody uses non-initialized list entries.#define LIST_POISON1(void*)0 x00100100)#define LIST_POISON2(void*)0 x00200200)常规思想是:entry-next=NULL;entry-prev=NULL;注意:Linux内核中
10、的=都与前后隔了一个空格,这样比紧靠前后要清晰。-list_del_init()-static inline void list_del_init(struct list_head*entry)_list_del(entry-prev,entry-next);INIT_LIST_HEAD(entry);删除entry所指向的结点,同时将entry所指向的结点的next,prev指针域指向自身。-list_move()-list_move_tail()-static inline void list_move(struct list_head*list,struct list_head*head
11、)_list_del(list-prev,list-next);list_add(list,head);将list结点前后两个结点互相指向彼此,删除list指针所指向的结点,再将此结点插入head,和head-next两个指针所指向的结点之间。即:将list所指向的结点移动到head所指向的结点的后面。linux内核学习之链表篇-ChinaUnix操作系统频道http:/ 21:43:59 static inline void list_move_tail(struct list_head*list,struct list_head*head)_list_del(list-prev,list-
12、next);list_add_tail(list,head);删除了list所指向的结点,将其插入到head所指向的结点的前面,如果head-prev指向链表的尾结点的话,就是将list所指向的结点插入到链表的结尾。-list_empty()-static inline int list_empty(const struct list_head*head)return head-next=head;注意:1.如果是只有一个结点,head,head-next,head-prev都指向同一个结点,则这里会返回1,但链表却不为空,仍有一个头结点 2.return 后面不带括号,且为一个表达式。3.测
13、试链表是否为空,但这个空不是没有任何结点,而是只有一个头结点。-list_empty_careful()-static inline int list_empty_careful(const struct list_head*head)struct list_head*next=head-next;return(next=head)&(next=head-prev);分析:1.只有一个头结点head,这时head指向这个头结点,head-next,head-prev指向head,linux内核学习之链表篇-ChinaUnix操作系统频道http:/ 21:43:59 即:head=head-n
14、ext=head-prev,这时候list_empty_careful()函数返回1。2.有两个结点,head指向头结点,head-next,head-prev均指向后面那个结点,即:head-next=head-prev,而head!=head-next,head!=head-prev.所以函数将返回0 3.有三个及三个以上的结点,这是一般的情况,自己容易分析了。注意:这里empty list是指只有一个空的头结点,而不是毫无任何结点。并且该头结点必须其head-next=head-prev=head -_list_splice()-static inline void _list_spli
15、ce(struct list_head*list,struct list_head*head)struct list_head*first=list-next;struct list_head*last=list-prev;struct list_head*at=head-next;first-prev=head;head-next=first;last-next=at;at-prev=last;-list_splice()-/*list_splice-join two lists *list:the new list to add.*head:the place to add it in t
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux 内核 学习 链表篇 ChinaUnix 操作系统 频道
限制150内