Linux双向链表操作

Linux双向链表实现

代码位于include/linux/list.h,链表初始化:

struct list_head {
    struct list_head *next, *prev;
};
static inline void INIT_LIST_HEAD(struct list_head *list)
{
    list->next = list;
    list->prev = list;
}
初始化后,链表状态图,框图左侧为prev指针,右侧为next指针:


利用list_add和list_add_tail函数插入新节点,前者插入新节点到链表头部,也就是head的next指针所指的位置,后者插入新节点到链表尾部,即head的prev指针所指位置,代码:

static inline void list_add(struct list_head *new, struct list_head *head)
{
    __list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
    __list_add(new, head->prev, head);
}

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;
}
首次插入新节点new1,无论是list_add还是list_add_tail函数,插入之后的链表框图相同:

Linux双向链表操作_第1张图片
继续调用list_add, list_add_tail函数插入第二个节点new2的框图如下:
Linux双向链表操作_第2张图片

双向链表循环代码:

#define list_for_each(pos, head) \
    for (pos = (head)->next; pos != (head); pos = pos->next)

循环处理首先由head的next指针开始,一直循环到节点head为止。处理的顺序与list_add_tail函数插入节点的顺序相反,与list_add插入节点的顺序相同。

list_for_each_entry循环遍历链表的所有元素,Linux源代码如下:

#define list_entry(ptr, type, member) \
    ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define list_for_each_entry(pos, head, member)                      \
    for (pos = list_entry((head)->next, typeof(*pos), member);      \
         &pos->member != (head);                                    \
         pos = list_entry(pos->member.next, typeof(*pos), member))
其中pos,是含有list_head类型的member成员的type类型结构体指针。但是链表头head并没有包含在type类型的结构体内,所以访问包含head的type类型指针其实是在访问一个不合理的地址,一种情况发生在list_for_each_entry遍历一个空表的时候;另一种情况是判断是否为链表的最后一个元素的时候。

你可能感兴趣的:(Linux双向链表操作)