linux中的list.h(2)

相关博文:
linux中的list.h(1) ——>内核链表简介,list_entry()方法。

依靠list_entry()方法,内核提供了创建/操作以及其他链表管理的各种例程,而所有这些方法都不需要知道list_head所嵌入对象的数据结构。

linux中的list.h(3) ——>内核链表的增加、删除、遍历

linux内核中链表的创建

linux内核中的双链表操作非常经典。为了加深对代码的理解,我将在用户态下对里面的内容进行一些实现。
注意list.h是在内核态中用的,在用户态直接#include 是不行的。不过,虽然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指针都指向自身。不过,需要注意的是,该链表头部并非是使用链表结构体的宿主节点,而仅是链表节点本身。
linux中的list.h(2)_第1张图片

list_test.h
linux中的list.h(2)_第2张图片

list_test.c
linux中的list.h(2)_第3张图片

结果:
这里写图片描述

定义一个链表

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)

你可能感兴趣的:(Linux内核)