内核链表
内核链表是纯粹的链表结构,只有向前向后的两个指针。将内核链表嵌套到我们自己所写的,有数据的结构体里面,这样便可以将我们所输入的数据连接起来。
参考文件:/usr/include/btrfs/list.h
下面先来分析list.h的一些基本功能。
插入数据
内核链表有很多巧妙之处,比如这里无论是头插还是尾插都是调用函数__list_add来实现。
static inline void __list_add(struct list_head *xnew,
struct list_head *prev,
struct list_head *next)
{
next->prev = xnew;
xnew->next = next;
xnew->prev = prev;
prev->next = xnew;
}
头插数据
static inline void list_add(struct list_head *xnew, struct list_head *head)
{
__list_add(xnew, head, head->next);
}
尾插数据
static inline void list_add_tail(struct list_head *xnew, struct list_head *head)
{
__list_add(xnew, head->prev, head);
}
删除节点
将链表中的某个节点删除。
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
查找节点
list_for_each将每个节点从链表中取出,list_entry将取出的节点进行运算,运算结果为用户定义的结构体地址(该节点)。通过遍历加list_entry运算,便可以访问链表中每一个数据的值,也可以将符合某个数据的值的节点地址返回。
#define list_for_each(pos, head)
for (pos = (head)->next; pos != (head);
pos = pos->next)
#define list_entry(ptr, type, member)
((type*)((char * )(ptr) - (unsigned long)(&((type*)0)->member)))
内核链表的使用
创建一个.c文件,包含/usr/include/btrfs/list.h。通过以上功能的分析,已经可以实现链表的增,删,改,查的功能。
#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
typedef struct kernel_list{
int data;
struct list_head kernel_head;
}my_kernel_list, *p_kernel_list;
int input_msg(char * msg)
{
// 让用户输入新的数据
int num ;
printf("%s:" , msg);
scanf("%d" , &num);
while(getchar() != '
');
return num;
}
p_kernel_list new_node()
{
p_kernel_list new = calloc(1, sizeof(my_kernel_list));
if(NULL == new)
{
printf("Node creation failed
");
return NULL;
}
INIT_LIST_HEAD(&new->kernel_head);
return new;
}
void insert_node(p_kernel_list head)
{
p_kernel_list new = new_node();
new->data = input_msg("Please enter the data for the header node");
list_add(&new->kernel_head, &head->kernel_head);
}
bool display_list(p_kernel_list head)
{
if (list_empty(&head->kernel_head))
{
printf("The linked list is empty. Printing failed
");
return false;
}
struct list_head *pos;
p_kernel_list tmp;
list_for_each(pos, &head->kernel_head)
{
tmp = list_entry(pos, my_kernel_list, kernel_head);
printf("data:%d
", tmp->data);
}
}
void add_tail_node(p_kernel_list head)
{
p_kernel_list new = new_node();
new->data = input_msg("Please enter the data for the tail node");
list_add_tail(&new->kernel_head, &head->kernel_head);
}
p_kernel_list find_node(p_kernel_list head, int fdata)
{
struct list_head *pos;
p_kernel_list tmp;
list_for_each(pos, &head->kernel_head)
{
tmp = list_entry(pos, my_kernel_list, kernel_head);
if (tmp->data == fdata)
{
return tmp;
}
}
return NULL;
}
bool del_node(p_kernel_list head)
{
int del_data = input_msg("Please enter the data you want to delete");
p_kernel_list del_pos;
del_pos = find_node(head, del_data);
if (NULL == del_pos)
{
printf("Failed to delete. No data available
");
return false;
}
list_del_init(&del_pos->kernel_head);
}
bool replace_node(p_kernel_list head)
{
p_kernel_list new = new_node();
p_kernel_list old_node;
int del_data = input_msg("Please enter the data that needs to be replaced");
old_node = find_node(head, del_data);
if (NULL == old_node)
{
printf("Replacement failed. No data available
");
return false;
}
int new_data = input_msg("Please enter new data");
new->data = new_data;
list_replace_init(&old_node->kernel_head, &new->kernel_head);
}
int main(int argc, char const *argv[])
{
p_kernel_list head = new_node();
insert_node(head);
insert_node(head);
add_tail_node(head);
add_tail_node(head);
display_list(head);
del_node(head);
display_list(head);
replace_node(head);
display_list(head);
return 0;
}