list_head的用法详解

更新时间:2023-06-18 15:08:02 阅读: 评论:0

list_head的⽤法详解
写贪吃蛇C语⾳代码,⼤多⽤到双向链表做蛇的数据结构体。如下:
typedef struct node /* Snake_node structur*{
int x_pos;
拉面怎么和面int y_pos;
struct node *prev;
struct node *next;
} Snake_Node;
另在⼀篇博⽂看到有这个概念:Linux内核的“侵⼊式链表”list_head“。优点:不⽤管理⼤量的链表节点内存了,因为“本⾝即链表”。故百度终结⽤法如下:
相关头⽂件include/linux/list.h
/*结构体原型*/
struct list_head {
struct list_head *next, *prev;
甘露寺在哪};
#define LIST_HEAD(name)      //定义并初始化头结点head
#define INIT_LIST_HEAD(ptr)      //初始化头结点ptr,因此需要⾸先定义ptr
_INLINE_ void list_add(struct list_head *add, struct list_head *head) //每次添加节点到head之后,始终都是添加到头结点之后
_INLINE_ void list_add_tail(struct list_head *add, struct list_head *head)//每次添加节点都是头结点之前,由于是循环链表,就是说添加到链表尾部
_INLINE_ void list_del(struct list_head *entry)//删除节点
_INLINE_ void list_del_init(struct list_head *entry)//删除节点,并初始化被删除的结点(也就是使被删除的结点的prev和next都指向⾃⼰)
_INLINE_ int list_empty(struct list_head *head)//判断链表是否为空
_INLINE_ void list_splice(struct list_head *list, struct list_head *head)//通过两个链表的head,进⾏连接
#define list_entry(ptr, type, member)    //通过偏移值取type类型结构体的⾸地址
#define list_for_each(pos, head)                  //遍历链表,循环内不可调⽤list_del()删除节点
#define list_for_each_safe(pos, pnext, head)      //遍历链表,可以同时有删除节点的操作
⼀:问题
传统双链表:
struct person {
int age;
int weight;
struct person *next, *prev;
};
采⽤侵⼊式链表:
struct person {
int age;
int weight;
struct list_head list;
};
爱的文章
可能⼜会有些⼈会问了,struct list_head都不是struct persionl类型,怎么可以做链表的指针呢?其实,⽆论是什么样的指针,它的⼤⼩都是⼀样的,32位的系统中,指针的⼤⼩都是32位(即4个字节),只是不同类型的指针在解释的时候不⼀样⽽已,那么这个struct list_head⼜是怎么去做这些结构的链表指针呢,那么就请看下⼀节。
⼆、struct list_head结构的操作
⾸先,让我们来看下和struct list_head有关的两个宏,它们定义在list.h⽂件中。
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
这两个宏是⽤了定义双向链表的头节点的,定义⼀个双向链表的头节点,我们可以这样:
struct list_head head;
LIST_HEAD_INIT(head);
⼜或者直接这样:
LIST_HEAD(head);
这样,我们就定义并初始化了⼀个头节点。
#define LIST_HEAD_INIT(name) { &(name), &(name) }
就是⽤head的地址初始化其两个成员next和prev ,使其都指向⾃⼰。
我们再看下和其相关的⼏个函数,这些函数都作为内联函数也都定义list.h中,这⾥要说明⼀下linux源码
的⼀个风格,在下⾯的这些函数中以下划线开始的函数是给内部调⽤的函数,⽽以符开始的函数就是对外使⽤的函数,这些函数⼀般都是调⽤以下划线开始的函数,或是说是对下划线开始的函数的封装。
2.1 增加节点的函数
static inline void __list_add();
static inline void list_add();
static inline void list_add_tail();
其实看源代码是最好的讲解了,这⾥我再简单的讲⼀下。
* __list_add - Inrt a new entry between two known concutive entries.
* @new:
* @prev:
* @next:
*
* This is only for internal list manipulation where we know the prev/next
* entries
*/
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;
}
//这个函数在prev和next间插⼊⼀个节点new。
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Inrt a new entry after the specified head.
* This is good for implementing stacks.
*/
static __inline__ void list_add(struct list_head *new, struct list_head *head) {
__list_add(new, head, head->next);
}
//这个函数在head节点后⾯插⼊new节点。
正确的金钱观/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Inrt a new entry before the specified head.
* This is uful for implementing queues.
*/
static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) {
__list_add(new, head->prev, head);
}
这个函数和上⾯的那个函数相反,它在head节点的前⾯插⼊new节点。
2.2 从链表中删除节点的函数
* __list_del -
* @prev:
* @next:
*
* Delete a list entry by making the prev/next entries point to each other.
*
* This is only for internal list manipulation where we know the prev/next
* entries
*/
static __inline__ void __list_del(struct list_head * prev,
struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* * Note: list_empty on entry does not return true after this, the entry is in
* an undefined state.
*/
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static __inline__ void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
天空壁纸}
这⾥简单说⼀下,list_del(struct list_head *entry)是从链表中删除entry节点。
list_del_init(struct list_head *entry) 不但从链表中删除节点,还把这个节点的向前向后指针都指
向⾃⼰,即初始化。
那么,我们怎么判断这个链表是不是空的呢!上⾯我说了,这⾥的双向链表都是有⼀个头节点,⽽我们上⾯看到,定义⼀个头节点时我们就初始化了,即它的prev和next指针都指向⾃⼰。所以这个函数是这样的。
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static __inline__ int list_empty(struct list_head *head)
{慈爱的意思
return head->next == head;
}
讲了这⼏个函数后,这⼜到了关键了,下⾯讲解的⼀个宏的定义就是对第⼀节中,我们所要说的为什么在⼀个
结构中加⼊struct list_head变量就把这个结构变成了双向链表呢,这其中的关键就是怎么通过这个
struct list_head变量来获取整个结构的变量,下⾯这个宏就为你解开答案:
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
乍⼀看下,不知道这个宏在说什么,没关系,我举个例⼦来为你⼀⼀解答:)
西白山⾸先,我们还是⽤上⾯的结构:
struct person
{
int age;
int weight;
struct list_head list;
新年第一天上班祝福语
};
我们⼀看到这样的结构就应该知道它定义了⼀个双向链表,下⾯来看下。
我们有⼀个指针:
struct list_head *pos;
现在有这个指针,我们怎么去获得这个指针所在的结构的变量(即是struct person变量,其实是struct
person指针)呢?看下⾯这样使⽤:
struct person *one = list_entry(pos, struct person, list);
不明⽩是吧,展开⼀下 list_entry结构如下:
((struct person *)((char *)(pos) - (unsigned long)(&((struct person *)0)->list)))
⽤个图形来说(unsigned long)(&((struct person *)0)->list,如下:
(char *)(pos):是将pos由struct list_head*转成char* ,指向list_head的地址。
(unsigned long)(&((struct person *)0)->list):先看最⾥⾯的(struct person *)0),它是把0地址转成struct person指针,然后(struct person *)0)->list就是指向list 变量,之后是 &((struct person *)0)->list是取这个变量的地址,最后是(unsigned long)(&((struct person *)0)->list)把这个变量的地址值变成⼀个整形数!
这么复杂啊,其实说⽩了,这个(unsigned long)(&((struct person *)0)->list)的意思就是取list变量在struct person结构中的偏移量。这⾥等于8。
知道这2个值即可得到person的地址了。
2.3 list_head 的遍历的宏

本文发布于:2023-06-18 15:08:02,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/1044167.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:链表   结构   节点   函数   定义
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图