相关博文:
linux中的list.h(1) ——>内核链表简介,list_entry()方法。
依靠list_entry()方法,内核提供了创建/操作以及其他链表管理的各种例程,而所有这些方法都不需要知道list_head
所嵌入对象的数据结构。
linux中的list.h(3) ——>内核链表的增加、删除、遍历
linux内核中链表的创建
linux内核中的双链表操作非常经典。为了加深对代码的理解,我将在用户态下对里面的内容进行一些实现。
注意list.h是在内核态中用的,在用户态直接#include <linux/list.h>
是不行的。不过,虽然list.h是内核代码中的头文件,但我们可以把它移植到用户空间使用。
list_head结构体原型
struct list_head {
struct list_head *next, *prev;
};
LIST_HEAD宏
/* 用两个宏来建立一个linux链表 */
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
/* 用一个内联函数来建立一个linux链表 */
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
无论是用宏还是内联函数来建立一个linux链表,都是用同一个对象来初始化next和prev。
主要是宏定义的不好理解。
其实LIST_HEAD(exp_list)
就相当于
struct list_head exp_list={&exp_list,&exp_list}
就相当于
struct list_head exp_list;
exp_list.next=&exp_list;
exp_list.prev=&exp_list;
struct list_head exp_list={&exp_list,&exp_list}
就是对结构体变量的初始化嘛。
struct student{
int num;
char name[10];
int age;
}
struct student stu1={010,"Ian",21};
LIST_HEAD(exp_list);
就是创建并初始化好的链表头部节点,其中next和prev指针都指向自身。不过,需要注意的是,该链表头部并非是使用链表结构体的宿主节点,而仅是链表节点本身。
list_test.h
list_test.c
结果:
定义一个链表
struct fox{
unsigned long weight;
bool is_cute;
struct list_head list;
}
把一个现有的数据结构(这里是fox结构体)改造为链表。
struct fox *red_fox;
red_fox=(struct fox*)malloc(sizeof(struct fox));
red_fox->weight=6;
red_fox->is_cute=false;
INIT_LIST_HEAD(&red_fox->list);
链表头
对上述代码进行简单修改,我们的fox结构便可以被内核链表例程管理。但在可以使用这些例程前,我们需要一个链表的头指针,来指向整个链表。
我们的fox节点都是无差别的,每一个节点都包含list_head指针,于是我们可以从任何一个节点起遍历链表,看到所有节点。不过,我们仍然需要一个头指针索引到整个链表,而不是从一个链表节点触发。
定义并初始化一个名为fox_list的链表例程。
LIST_HEAD(fox_list)