Linux内核链表学习笔记

本文介绍Linux内核中双向循环链表的实现原理及基本操作,包括初始化、插入及遍历等,并提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内核的链表一般都是双向循环链表,双向循环链表的效率是最高的,找头节点,尾节点,直接前驱,直接后继时间复杂度都是O(1),而使用单链表,单向循环链表或其他形式的链表是不能完成的。

链表的数据结构,定义在includ/linux/list.h下

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


定义一个带数据域的数据类型mystruct
struct mystruct {
     int data ;
     struct list_head mylist ;
} ;

一、初始化

1.宏:

#define LIST_HEAD_INIT(name){&(name), &(name)}

2.函数

<span style="font-family:SimSun;font-size:18px;"><strong>static inline void INIT_LIST_HEAD(struct list_head *list){
<span style="white-space:pre">	</span>list->next=list;
<span style="white-space:pre">	</span>list->prev=list;
}</strong></span>


定义两个mystruct型变量 first, second 并分别用两种方法初始化它们的指针:

<span style="font-family:SimSun;font-size:18px;"><strong>struct mystruct first ={
	.data=10,
	.mylist=LIST_HEAD_INIT(first.mylist)
};

struct mystruct second;
second.data=20;
INIT_LIST_HEAD(&second.mylist);</strong></span>



现在需要一个变量以代表链表的表头,使用LIST_HEAD宏将其初始化为空表

<strong><span style="font-family:SimSun;font-size:18px;">#define LIST_HEAD(name) struct list_head name=LIST_HEAD_INIT(name)</span></strong>
LIST_HEAD(mylinkedlist);


二、插入

<strong><span style="font-family:SimSun;font-size:18px;">list_add ( &first.mylist , &mylinkedlist ) ;
list_add ( &second.mylist , &mylinkedlist ) ;</span></strong>

list_add是如下定义的函数

<strong><span style="font-family:SimSun;font-size:18px;">static inline void list_add(struct list_head *new, struct list_head *head) 
{ 
        __list_add(new, head, head->next); 
} 
</span></strong>

内部函数__list_add:

<strong><span style="font-family:SimSun;font-size:18px;"> 
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; 
} 
</span></strong>

三、遍历


1.遍历宏

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


2.由成员变量地址求结构体类型的地址

我们有地址struct list_head域的地址,但是没有包含它的结构体类型(暂时叫他目标类型)的地址,使用list_entry宏获得目标类型的地址

#define list_entry(ptr, type, member) container_of(ptr, type, member)
ptr 成员变量指针(list_head指针)

type结构体类型(mystruct类型,目标类型)

member成员变量(mylist)

container_of宏定义在[include/linux/kernel.h]中:
#define container_of(ptr, type, member) ({			\
        const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
        (type *)( (char *)__mptr - offsetof(type,member) );})
offsetof宏定义在[include/linux/stddef.h]中:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

遍历:

struct list_head *position=NULL;

struct mystruct *datastructureptr=NULL;

list_for_each(position,mylinkedlist){

datastructureptr=list_entry(position,struct mystruct,mylist);

         printk("data=%d/n",datastructureptr->data);

}


更方便的一个宏

418 #define list_for_each_entry(pos, head, member)                          \ 
419         for (pos = list_entry((head)->next, typeof(*pos), member);      \ 
420              &pos->member != (head);        \ 
421              pos = list_entry(pos->member.next, typeof(*pos), member)) 
422


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值