内核链表
1.定义
1.1 设计一个不存数据的双向循环链表
1.2 链表结构体
struct list_head{
struct list_head * prev;
struct list_head * next;
}
设计操作链表的接口都与数据无关(使用通用接口---在内核中有现成接口)。
1.3 例子
1.3.1 如果存数据
设计一个数据结构体Student, 在里面包含一个链表结构体struct list_head的成员list, 把每一个数据结构体里面的链表结构体,连接成一个双向循环链表。
1.3.2 通过结构体成员来计算结构体地址
⭐//在linux内核中提取内核链表模板
/usr/src/linux-headers-6.5.0-18-generic/include/linux/list.h
1.3.3 应用案例
从内核中提取出来list.h
list.h代码:
#ifndef _LINUX_LIST_
#define _LINUX_LIST_
#include <stdbool.h>
#include <stdio.h>
// 定义链表结构体
struct list_head {
struct list_head *next, *prev; // 指向前后节点的指针
};
// 计算结构体成员的偏移量
// type为结构体类型
// member为结构体内的链表成员
#define offsetof(type, member) (char*)(&((type*)0)->member)
// 通过链表指针获取数据结构体指针
// ptr指的是要求的结构体的链表成员
#define container_of(ptr, type, member) ({ ((type *)((char*)ptr - offsetof(type, member))); })
// 通过链表指针获取其所在的结构体指针
#define list_entry(ptr, type, member) container_of(ptr, type, member)
// 初始化一个链表头
#define LIST_HEAD_INIT(name) { &(name), &(name) }
// 定义链表头变量
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
// 初始化链表头,使其指向自身
static inline void INIT_LIST_HEAD(struct list_head *list)
{
if(list == NULL) return;
list->next = list;
list->prev = list;
}
// 插入一个新节点到指定位置
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(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;
}
// 删除链表中的一个节点
static inline void __list_del_entry(struct list_head *entry)
{
if(entry == NULL) return;
__list_del(entry->prev, entry->next);
}
// 删除节点并使其指针指向自身
static inline void list_del(struct list_head *entry)
{
__list_del_entry(entry);
entry->next = entry;
entry->prev = entry;
}
// 获取链表中的第一个节点
#define list_first_entry(ptr, type, member) list_entry((ptr)->next, type, member)
// 判断当前节点是否为链表头
#define list_entry_is_head(pos, head, member) (&pos->member == (head))
// 获取下一个节点
#define list_next_entry(pos, member) list_entry((pos)->member.next, typeof(*(pos)), member)
// 遍历链表(不可删除节点)
#define list_for_each_entry(pos, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member); \
!list_entry_is_head(pos, head, member); \
pos = list_next_entry(pos, member))
// 安全遍历链表(可删除节点)
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member), \
n = list_next_entry(pos, member); \
!list_entry_is_head(pos, head, member); \
pos = n, n = list_next_entry(n, member))
#endif // _LINUX_LIST_
应用案例代码:
#include "list.h"
#include <stdio.h>
#include <stdlib.h>
//设计一个数据结构体(学生结构体)
struct Student {
char name[32];
char sex[2];
int number;
struct list_head list;
};
int main(void)
{
struct Student *shead = malloc(sizeof(struct Student));
INIT_LIST_HEAD(&shead->list);
for(int i=0; i<3; i++){
//申请数据结构体空间
struct Student *pstu = malloc(sizeof(struct Student));
printf("请输入姓名,性别,学号:");scanf("%s %s %d", pstu->name, pstu->sex, &pstu->number);
//初始化链表结构体
INIT_LIST_HEAD(&pstu->list);
//把新建的数据结构体添加到头中
list_add_tail(&pstu->list, &shead->list);
}
//遍历输出
struct Student *pos = NULL;
list_for_each_entry(pos, &shead->list, list){
printf("%s--%s---%d\n", pos->name, pos->sex, pos->number);
}
}
本文来自博客园,作者:cyt2730,转载请注明原文链接:https://www.cnblogs.com/cytwjyy/p/18878751

浙公网安备 33010602011771号