Linux链表

JoyboyCZ
发布于 2023-3-29 17:27
浏览
0收藏

linux创建及初始化链表

动态方法

通过struct list_head创建,INIT_LIST_HEAD初始化。(list_head以及INIT_LIST_HEAD位于***<u><linux/list.h></u>***)

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

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

struct list_head mylist;
INIT_LIST_HEAD(&mylist)

静态方法

静态分配通过LIST_HEAD宏完成:

#define LIST_HEAD_INIT(name) {
	&(name), &(name)
}
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name) /* 将list_head的前后指针都指向name本身 */

LIST_HEAD(mylist)

创建链表节点

要创建新节点,只需创建数据结构实例,并初始化嵌入其中的list_head。

举例:

struct person {
	int age;
	string sex;
	string name;
	struct list_head list;
};
struct person *laowang = kzalloc(sizeof(struct person), GFP_KERNEL);
LIST_HEAD_INIT(&laowang->list);

关于kzalloc申请内存可参考Linux内核空间内存申请函数kmalloc、kzalloc、vmalloc的区别【转】 - sky-heaven - 博客园 (cnblogs.com)

添加链表节点

内核提供的list_add用于向链表添加新项,它是内部函数__list_add的包装:

static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next)
{
	next->prev = new;
	next->next = next;
	new->prev = prev;
	prev->next = new;
}
void list_add(struct list_head *new, struct list_head *head);	/* 这种模式科研用来实现堆栈 */
static inline void list_add(strcut list_head *new, struct list_head *head)
{
	__list_add(new, head, head->next);
}

static LIST_HEAD(person_list);	/* 如何使用呢? 需要先创建一个struct list_head变量 */
list_add(&zhangsan->list, &person_list);	/* 之后将节点添加到person_list中 */

还有另一个函数可以将节点添加到链表:

void list_add_tail(struct list_head *new, struct list_head *head)
{
	 __list_add(new, head->prev, head);		/* 这种模式可以用来实现队列 */
}

删除链表节点

static inline void list_del(struct list_head *entry) 	/* entry:要删除的链表的首地址 */
{
	__list_del(entry->prev, entry->next);
	entry->next = LIST_POISON1;		/* LIST_POISON1/2皆为NULL,详细位于/linux/poison.h */
	entry->prev = LIST_POISON2;
}
static inline void list_del_init(struct list_head *entry)
{
	__list_del_entry(entry);
	INIT_LIST_HEAD(entry); // 运行中初始化链表节点
}
static inline void __list_del_entry(struct list_head *entry)
{
	__list_del(entry->prev, entry->next);
}

list_del只是移除该节点,分配给该节点的内存需要使用kfree手动释放。

链表遍历

使用宏list_for_each_entry(pos, head, member)进行链表遍历。

  • head:链表头节点
  • member:数据结构中链表struct list_head的名称
  • pos:用于迭代。它是一个循环游标,就像for(i=0; i<foo; i++)中的i。head可以是链表头节点或任一项。(内核开发者只实现了循环双链表)
#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))
     
#define list_entry(ptr, type, member) \
    container_of(ptr, type, member)

收藏
回复
举报
回复
    相关推荐