unix内核链表说明与使用案例

代码是最好的老师,本文以代码展示为主。


要想使用内核链表,就要在结构体中包含struct list_head类型的变量,该变量将每个元素串联起来,构成一个双向链表。


struct list_head双向链表节点

struct list_head {
	struct list_head *next;
	struct list_head *prev;
};

链表头初始化:使用链表前,必须初始化链表头部

// 初始化链表头
#define INIT_LIST_HEAD(head) do {			\
		(head)->next = (head)->prev = head;	\
	} while (0)

插入

// 在head元素后面,插入new
1. 如果head是链表头,则: 头插
2. 如果head是元素,则:在元素后,插入new (将new插入到head后面)
static inline void
list_add (struct list_head *new, struct list_head *head)
{
	new->prev = head;
	new->next = head->next;
	new->prev->next = new;
	new->next->prev = new;
}
// 尾插:
1. 如果head是链表头,则:尾插
2. 如果head是元素,则:在元素前,插入new (将new插入到head前面)
static inline void
list_add_tail (struct list_head *new, struct list_head *head)
{
	new->next = head;
	new->prev = head->prev;
	new->prev->next = new;
	new->next->prev = new;
}

删除

// 删除链表中的节点(不要使用,比较危险,因为old没有prev/next没设置为NULL)
static inline void
list_del (struct list_head *old)
{
	old->prev->next = old->next;
	old->next->prev = old->prev;
	old->next = (void *)0xbabebabe;
	old->prev = (void *)0xcafecafe;
}
// 删除链表中的节点(推荐使用,安全)
static inline void
list_del_init (struct list_head *old)
{
	old->prev->next = old->next;
	old->next->prev = old->prev;
	old->next = old;
	old->prev = old;
}

移动move

// 将元素list从表中删除,头插入链表head中/将插入到head后面
static inline void
list_move (struct list_head *list, struct list_head *head)
{
	list_del (list);
	list_add (list, head);
}
// 将元素list从表中删除,尾插入链表head中/插入到head前面
static inline void
list_move_tail (struct list_head *list, struct list_head *head)
{
	list_del (list);
	list_add_tail (list, head);
}

链表判空

/**
 * 判断链表是否为空
 * @return 空,1;非空,0
 */
static inline int
list_empty (struct list_head *head)
{
	return (head->next == head);
}

链表拼接

static inline void
__list_splice (struct list_head *list, struct list_head *head)
{
	(list->prev)->next = (head->next);
	(head->next)->prev = (list->prev);
	(head)->next = (list->next);
	(list->next)->prev = (head);
}
/*
	拼接两个链表:
	1.如果新增的链表只有一个链表头就不做任何处理(因为链表头不包含数据)
	2. (head 2 3) + (add 5 6)    
	  ==> (head 5 6 2 3)  //抛弃链表头add
*/
static inline void
list_splice (struct list_head *list, struct list_head *head)
{
	if (list_empty (list))
		return;

	__list_splice (list, head);
}

/* Splice moves @list to the head of the list at @head. */
static inline void
list_splice_init (struct list_head *list, struct list_head *head)
{
	if (list_empty (list))
		return;

	__list_splice (list, head);
	INIT_LIST_HEAD (list);
}

/* Splice moves @list to the tail of the list at @head. */
static inline void
list_splice_tail_init (struct list_head *list, struct list_head *head)
{
	if (list_empty (list))
		return;

	__list_splice (list, head->prev);
	INIT_LIST_HEAD (list);
}

static inline void
__list_append (struct list_head *list, struct list_head *head)
{
	(head->prev)->next = (list->next);
	(list->next)->prev = (head->prev);
	(head->prev) = (list->prev);
	(list->prev)->next = head;
}

static inline void
list_append (struct list_head *list, struct list_head *head)
{
	if (list_empty (list))
		return;

	__list_append (list, head);
}

/* Append moves @list to the end of @head */
static inline void
list_append_init (struct list_head *list, struct list_head *head)
{
	if (list_empty (list))
		return;

	__list_append (list, head);
	INIT_LIST_HEAD (list);
}

#define list_next(ptr, head, type, member)      \
        (((ptr)->member.next == head) ? NULL    \
             : list_entry((ptr)->member.next, type, member))

获取list所处对象的地址

/**
list_for_each(iter, &stu_list_head->list) {
	stu_node = list_entry(iter, stu_list_t, list);  
	printf("id = %d, name = %s\n", stu_node->student->id, stu_node->student->name);
}

等价于 list_for_each_entry()

#define GET_LAST_NODE(set)  \
    list_entry(set.list.prev, typeof(df_file), slist)
*/
#define list_entry(ptr, type, member)					\
	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

遍历链表

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

#define list_for_each_safe(pos, n, head) \
        for (pos = (head)->next, n = pos->next; pos != (head); \
            pos = n, n = pos->next)
/**
 *    遍历(打印)链表
 * @example
 *     stu_list_t* entry;  // 必须是结构体类型
		// lhead类型:struct list_head*
		// list:是stu_list_t结构体中的struct list_head的member名字
		list_for_each_entry(entry, lhead, list)
		{
			printf("id=%d, name=%s\n",entry->student->id, entry->student->name);
		}
 */
#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))

/**
 *    遍历(删除)链表
 * @param [in] stu_list_t *  pos    当前元素
 * @param [in] stu_list_t *  n
 * @param [in] list_head*    head  	链表的头结点
 * @param [in] member   stu_list_t结构体中list成员名
 * @example 
	stu_list_t* entry, * tmp;  // 必须是结构体类型
	// lhead类型:struct list_head*
	// list:是stu_list_t结构体中的struct list_head的member名字
	list_for_each_entry_safe(entry, tmp, lhead, list)
	{
		// 从链表中删除节点
		list_del(&entry->list);
		
		// 释放
		free(entry->student);
		free(entry);
	}
 */
#define list_for_each_entry_safe(pos, n, head, member)			\
	for (pos = list_entry((head)->next, typeof(*pos), member),	\
		n = list_entry(pos->member.next, typeof(*pos), member);	\
	     &pos->member != (head); 					\
	     pos = n, n = list_entry(n->member.next, typeof(*n), member))

#define list_for_each_entry_reverse(pos, head, member)                  \
	for (pos = list_entry((head)->prev, typeof(*pos), member);      \
	     &pos->member != (head);                                    \
	     pos = list_entry(pos->member.prev, typeof(*pos), member))

#define list_for_each_entry_safe_reverse(pos, n, head, member)          \
	for (pos = list_entry((head)->prev, typeof(*pos), member),      \
	        n = list_entry(pos->member.prev, typeof(*pos), member); \
	     &pos->member != (head);                                    \
	     pos = n, n = list_entry(n->member.prev, typeof(*n), member))

#endif /* _LLIST_H */

代码案例

#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>

typedef struct stu {
    int id;
    char name[10];
} stu_t;

typedef struct {
    struct list_head list;  // 简单理解,只要在struct中包含了struct list,该结构体就变成一个链表
    stu_t *student;  // 数据
} stu_list_t;

stu_list_t *new_stu(int i)
{
    stu_list_t  *stu_node = (stu_list_t *)malloc(sizeof(stu_list_t));
    stu_node->student = (stu_t *)malloc(sizeof(stu_t));
    stu_node->student->id = i;
    sprintf(stu_node->student->name, "%d", i);

    return stu_node;
}

// 遍历打印
void list_travel(struct list_head* lhead)
{
    stu_list_t* entry;
    list_for_each_entry(entry, lhead, list)
    {
        printf("id=%d, name=%s\n",entry->student->id, entry->student->name);
    }
}

// 遍历删除
void list_free(struct list_head* lhead)
{
    stu_list_t* entry, * tmp;

    list_for_each_entry_safe(entry, tmp, lhead, list)
    {
        // 从链表中删除节点
        list_del(&entry->list);        
        // 释放
        free(entry->student);
        free(entry);
    }
}

int main()
{
    struct list_head lhead;

    // 初始化链表
    INIT_LIST_HEAD(&lhead);

    // 创建学生节点,插入链表lhead
    int i;
    for (i = 0; i < 5; i++) {
        // 创建学生节点
        stu_list_t *stu_node = new_stu(i);
        // 将学生节点,插入到链表中
        list_add(&stu_node->list, &lhead);  // 头插
    }
    
    list_travel(&lhead);
    printf("empty = %d\n", list_empty(&lhead));  // 0 表示不空

    list_free(&lhead);
    printf("empty = %d\n", list_empty(&lhead));  // 1 表示空

    list_travel(&lhead);
    
    return 0;
}

问题

代码中,出现 struct list_head list;,此处的 list 表示什么含义呢?

此处有2层含义:

① 在结构体中,仅仅表示该结构体能够通过list这个member,连接成一个链表
注意:该成员不需要初始化。 将结构体插入链表,本质上是将结构体中的list成员插入链表

typedef struct {
    int sno;
    struct list_head list;  // 表示node_t节点可以通过list构成一个链表
} node_t;

int main()
{
    struct list_head  lhead;  // 作为链表头,表示一个链表
    INIT_LIST_HEAD(&lhead);

    node_t nd;
    nd.sno = 100;
    // nd.list不用初始化

    list_add(&nd.list, &lhead);
}

② 作为链表头,表示一个链表
注意:必须被初始化。 可以将结构体插入到该链表

#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>

typedef struct {
    int sno;
    struct list_head list;  // 表示node_t节点可以通过list构成一个链表
} node_t;

typedef struct {
    int node_cnt;
    struct list_head nodes_hd;  // 作为链表头,表示一个链表
} bignode_t;

int main()
{
    // 1.初始化bignode_t
    bignode_t *bnd = malloc(sizeof(bignode_t));
    bnd->node_cnt = 0;
    INIT_LIST_HEAD(&bnd->nodes_hd);

    // 2.创建node_t节点
    node_t *nd = malloc(sizeof(nd));
    nd->sno = 1008611;

    // 3.将nd插入到链表nodes_hd中
    list_add(&nd->list, &bnd->nodes_hd);
    bnd->node_cnt++;
}

① ② 代码综合案例

#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>

typedef struct {
    int sno;
    struct list_head list;  // 表示node_t节点可以通过list构成一个链表
} node_t;

typedef struct {
    int node_cnt;
    struct list_head list;  // 表示bignode_t节点可以通过list构成一个链表

    struct list_head nodes_hd;  // 表示链表头(在此处,该链表元素类型是node_t)
} bignode_t;


int main()
{
    // 1.初始化bignode_t
    bignode_t *bnd = malloc(sizeof(bignode_t));
    bnd->node_cnt = 0;
    INIT_LIST_HEAD(&bnd->nodes_hd);

    // 2.创建node_t节点
    node_t *nd = malloc(sizeof(nd));
    nd->sno = 1008611;

    // 3.将nd插入到链表nodes_hd中
    list_add(&nd->list, &bnd->nodes_hd);
    bnd->node_cnt++;

    struct list_head bignds_hd;
    INIT_LIST_HEAD(&bignds_hd);
    list_add(&bnd->list, &bignds_hd);  // bnd又作为元素,插入到bignds_hd链表中
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值