内核链表详解 (struct list_head)

1.自己实现内核链表的部分
2.内核链表使用举例

#include <stdio.h>

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

#define LIST_HEAD_INIT(name) { &(name), &(name) } 
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name) 

/*
1.向链表中添加节点,普通的在两个非空结点中插入一个结点,注意new、prev、next都不能是空值
2.Prev可以等于next,此时在只含头节点的链表中插入新节点。
3.只有头结点的时候,头部插入和尾部插入没有区别
*/
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;
} 

//头部插入,插在头结点之后,
static inline void list_add_head(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_del(struct list_head * prev, struct list_head * next) 
{ 
	next->prev = prev; 
	prev->next = next; 
}

//删除entry所指的结点,同时将entry所指向的结点指针域封死
static inline void list_del(struct list_head *entry) 
{ 
	__list_del(entry->prev, entry->next);
	entry->next = NULL;
	entry->prev = NULL;
}

//移动节点
//将entry所指向的结点移动到head所指向的结点的后面。 
static inline void list_move_head(struct list_head *entry, struct list_head *head) 
{ 
	__list_del(entry->prev, entry->next); 
	list_add_head(entry, head);
}

//删除了list所指向的结点,将其插入到head所指向的结点的前面,
//如果head->prev指向链表的尾结点的话,就是将list所指向的结点插入到链表的结尾
static inline void list_move_tail(struct list_head *entry, struct list_head *head) 
{ 
	__list_del(entry->prev, entry->next);
	list_add_tail(entry, head);
}

//判断是否为空链表 
//由list-head构成的双向循环链表中,通常有一个头节点,其不含有有效信息,
//初始化时prev和next都指向自身。判空操作是判断除了头节点外是否有其他节点。 
//试链表是否为空,如果是只有一个结点,head,head->next,head->prev都指向同一个结点,则这里会返回1,
//表示空;但这个空不是没有任何结点,
//而是只有一个头结点,因为头节点只是纯粹的list节点,没有有效信息,故认为为空
static inline int list_empty(const struct list_head *head) 
{ 
	return head->next == head; 
}

static inline int list_empty_careful(const struct list_head *head) 
{ 
	struct list_head *next = head->next;
	return (next == head) && (next == head->prev);
}

//链表合并 
static inline void __list_splice(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; 
}

static inline void list_splice(struct list_head *list, struct list_head *head) 
{ 
	if (!list_empty(list)) 
		__list_splice(list, head);
}

/*
作用:找到成员与结构体开始地址的偏移

TYPE:大结构体的类型
MEMBER:大结构体中成员的名称
*/
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
/*
作用:通过成员的指针找到大结构体的指针

ptr 结构体成员的指针
type 大结构体的类型
member ptr代表的成员在大结构体的名称
*/
#define container_of(ptr, type, member) ({                      \
    const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
    (type *)( (char *)__mptr - offsetof(type,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) 

#define list_entry(ptr, type, member) \
container_of(ptr, type, member)

/*
pos:大结构体的指针
head:头结点
member: struct list_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))

//相比于list_for_each_entry,list_for_each_entry_safe用指针n对链表的下一个数据结构进行了临时存储,
//所以如果在遍历链表的时候需要做删除链表中的当前项操作时,用list_for_each_entry_safe可以安全的删除,
//而不会影响接下来的遍历过程(用n指针可以继续完成接下来的遍历, 而list_for_each_entry则无法继续遍历,
//删除后会导致无法继续遍历)
/*
pos:大结构体的指针
n:大结构体的指针,是一个备份
head:头结点
member: struct list_head 在大结构体中的名称
*/
#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))

struct student
{
	int id;
	int age;
	struct list_head entry;
};

int main(int argc, char const *argv[])
{
	struct student * pos_st = NULL;
	struct student * pos_n = NULL;
	LIST_HEAD(list_head_obj);//struct list_head list_head_obj = {&list_head_obj, &list_head_obj};
	struct student STA = {0, 21, {NULL, NULL}};
	struct student STB = {1, 22, {NULL, NULL}};
	struct student STC = {2, 23, {NULL, NULL}};
	struct student STD = {4, 66, {NULL, NULL}};

	list_add_tail(&STA.entry, &list_head_obj);
	list_add_tail(&STB.entry, &list_head_obj);
	list_add_tail(&STC.entry, &list_head_obj);
	list_add_head(&STD.entry, &list_head_obj);

	list_for_each_entry(pos_st, &list_head_obj, entry)
	{
		printf("id:[%d]  age[%d]\n", pos_st->id, pos_st->age);
	}

	list_for_each_entry_safe(pos_st, pos_n, &list_head_obj, entry)
	{
		printf("id:[%d]  age[%d]\n", pos_st->id, pos_st->age);
	}

	return 0;
}

部分资源来源于网络,若有侵权,请联系作者删除。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值