目录
- 一、概述
- 二、详细使用步骤
- ✨2.1 定义结构体包含 struct list_head 成员
- ✨2.2 初始化链表头结点:INIT_LIST_HEAD
- ✨2.3 添加结点:list_add、list_add_tail
- ✨2.4 遍历链表:list_for_each、list_for_each_safe、list_for_each_entry
- ✨2.5 获取结构体数据:list_entry
- ✨2.6 删除结点:list_del
- ✨2.7 判断是否空链表:list_empty
- 三、list.h 使用例子源码
- 四、例子中使用的 list.h 代码
- 五、抽取常用函数组成的简约版list.h —— my_list.h
一、概述
前面文章【数据结构】list.h 常用函数实现详解 介绍过 list.h 的函数实现,这篇文章打算结束一下 list.h 的使用步骤,基本步骤有下面几个:
-
- 定义结构体时必须包含 struct list_head 成员
-
- 初始化链表头结点:
INIT_LIST_HEAD(&studentsList);
- 初始化链表头结点:
-
- 添加结点:
list_add(&pXiaoMing->list_node, &studentsList); // 链表头部插入
list_add_tail(&pZero->list_node, &studentsList); // 链表尾部插入
- 添加结点:
-
- 遍历链表:
list_for_each_safe(pos,tmp,listHead) // 对列表进行迭代,以防删除列表条目。
list_for_each_entry(pListEntry, listHead, list_node) // 迭代给定类型的列表,遍历各个条目
list_for_each(pos,listHead) // 对列表进行迭代,一般用 list_for_each_safe
- 遍历链表:
-
- 获取结构体数据:
list_entry(pos,stStudentData,list_node); // 获取当前 struct list_head 的结构体指针
list_entry(studentsList.next,stStudentData,list_node); // 链表第一个结构体指针
list_entry(studentsList.prev,stStudentData,list_node); // 链表最后一个结构体指针
== 注意== :获取结构体指针之前,需要先判断链表是否为空,list_entry在空链表依然可以获取到数据,这显然不是想要的结果
- 获取结构体数据:
-
- 删除结点
list_del(pos); // 从列表中删除条目。
- 删除结点
-
- 判断是否空链表
list_empty(list); // 判断空链表
- 判断是否空链表
二、详细使用步骤
✨2.1 定义结构体包含 struct list_head 成员
list.h 添加和删除结点都是通过操作struct list_head
指针的,所以结点的结构体必须包含struct list_head
成员。struct list_head
成员一般放在结构体的最后一个,比较显眼,但这不是必须的。可以参考下面代码定义链表结点结构体:
// 1、定义的结构体必须包含 struct list_head 成员,才可以作为链表结点 2023-09-23 21:30:14
typedef struct studentData
{
int age;
int num;
struct list_head list_node;
char gender[10];
char name[10];
}stStudentData, *pstStudentData;
✨2.2 初始化链表头结点:INIT_LIST_HEAD
list.h是带有头结点的,并且操作链表时,很多时候也需要头结点。可以参考下面代码定义并初始化头结点:
// 2、定义并初始化头结点
struct list_head studentsList;// 头结点
INIT_LIST_HEAD(&studentsList);
✨2.3 添加结点:list_add、list_add_tail
初始化头结点后,就可以添加结点了,list.h 提供了两种方式添加结点:头部添加、尾部添加,可以参考下面代码添加自己结点:
// 3.1、在链表头部插入数据 list_add
pstStudentData pXiaoMing=(pstStudentData)malloc(sizeof(stStudentData));
pXiaoMing->age = 10;
pXiaoMing->num = 1;
sprintf(pXiaoMing->gender,"%s","boy");
sprintf(pXiaoMing->name,"%s","XiaoMing");
list_add(&pXiaoMing->list_node, &studentsList);
pstStudentData pXiaoHua=(pstStudentData)malloc(sizeof(stStudentData));
pXiaoHua->age = 11;
pXiaoHua->num = 2;
sprintf(pXiaoHua->gender,"%s","girl");
sprintf(pXiaoHua->name,"%s","XiaoHua");
list_add(&pXiaoHua->list_node, &studentsList);
// 3.2、在链表尾部插入数据 list_add_tail
pstStudentData pZero=(pstStudentData)malloc(sizeof(stStudentData));
pZero->age = 8;
pZero->num = 0;
sprintf(pZero->gender,"%s","boy");
sprintf(pZero->name,"%s","zero");
list_add_tail(&pZero->list_node, &studentsList);
✨2.4 遍历链表:list_for_each、list_for_each_safe、list_for_each_entry
list_for_each(pos, head)
:是一个宏,展开后是for循环,pos是作为迭代指针,指向各个结点;list_for_each_safe(pos, n, head)
:与list_for_each一样,可以防止误删结点,较常用;list_for_each_entry(pos, head, member)
:可以直接迭代访问结构体类型,pos指向结构体类型地址。
使用方法参考下面代码:
// 4、遍历链表
void print_list(struct list_head *listHead)
{
struct list_head *pos,*tmp;
pstStudentData pListEntry; // 链表条目 2023-09-23 22:07:14
list_for_each(pos,listHead)
{
pListEntry = list_entry(pos,stStudentData,list_node);
printf("list_for_each: num=%d, name=[%s], gender=[%s], age=%d, \n",
pListEntry->num, pListEntry->name, pListEntry->gender, pListEntry->age);
}
/*
* 对列表进行迭代,以防删除列表条目。
* pos: 要用作循环计数器的&struct list_head。指向迭代的条目的指针;
* tmp: 另一个 &struct list_head, 用作临时存储(外部没作用);
* listHead: 链表头指针 2023-09-23 22:18:11
*/
list_for_each_safe(pos,tmp,listHead)
{
/*
* 获取当前 struct list_head 的结构体指针
* pos: struct list_head指针。
* stStudentData: 包含 struct list_head 的结构体类型名称
* list_node: 结构中 struct list_head 的成员名称。
*/
// 5. 获取当前 struct list_head 的结构体指针
pListEntry = list_entry(pos,stStudentData,list_node);
printf("list_for_each_safe: num=%d, name=[%s], gender=[%s], age=%d, \n",
pListEntry->num, pListEntry->name, pListEntry->gender, pListEntry->age);
}
/*
* 迭代给定类型的列表
* pListEntry: 要用作循环计数器的类型指针
* listHead: 链表头指针 2023-09-23 22:18:11
* list_node: 结构中list_struct的名称。
*/
list_for_each_entry(pListEntry, listHead, list_node)
{
printf("list_for_each_entry: num=%d, name=[%s], gender=[%s], age=%d, \n",
pListEntry->num, pListEntry->name, pListEntry->gender, pListEntry->age);
}
}
✨2.5 获取结构体数据:list_entry
list_entry
可以通过 struct list_head*
指针获取到结构体的首地址,进而对结构体数据进行访问;
注意:获取结构体指针之前,需要先判断链表是否为空,list_entry在空链表依然可以获取到数据,这显然不是想要的结果。
list_entry(ptr, type, member)
函数参数:
- ptr: struct list_head指针。
- type: 包含 struct list_head 的结构体类型名称
- member: 结构中 struct list_head 的成员名称。
使用方法参考下面代码:
// 5.获取结构体数据 2023-09-24 21:18:02
pstStudentData pFirst = list_entry(studentsList.next,stStudentData,list_node);
//pstStudentData pFirst = list_first_entry(&studentsList,stStudentData,list_node);
printf("pFirst: num=%d, name=[%s], gender=[%s], age=%d, \n",
pFirst->num, pFirst->name, pFirst->gender, pFirst->age);
pstStudentData pLast = list_entry(studentsList.prev,stStudentData,list_node);
//pstStudentData pLast = list_last_entry(&studentsList,stStudentData,list_node);
printf("pLast: num=%d, name=[%s], gender=[%s], age=%d, \n",
pLast->num, pLast->name, pLast->gender, pLast->age);
✨2.6 删除结点:list_del
list_del
函数可以删除指定的结点。使用方法参考下面代码:
void clear_list(struct list_head *listHead)
{
struct list_head *pos,*tmp;
pstStudentData pListEntry; // 链表条目 2023-09-23 22:07:14
list_for_each_safe(pos,tmp,listHead)
{
pListEntry = list_entry(pos,stStudentData,list_node);
printf("del: num=%d, name=[%s], gender=[%s], age=%d, \n",
pListEntry->num, pListEntry->name, pListEntry->gender, pListEntry->age);
/*
* 从列表中删除条目。
* pos: 要从列表中删除的元素。struct list_head *
*/
list_del(pos);
free(pListEntry);
}
}
✨2.7 判断是否空链表:list_empty
list_empty
:只需要传入链表头结点,就可以判断链表是否为空,为空返回真,不空返回假;
使用方法参考下面代码:
// 7.判断空链表
if(list_empty(&studentsList))
{
pstStudentData pFirst = list_entry(studentsList.next,stStudentData,list_node);
if(pFirst==NULL)
printf("list is empty\n");
else
printf("list is empty,error fist %p\n", pFirst);
}
三、list.h 使用例子源码
将前面的示例代码整合起来就是一个使用 list.h 例子,代码如下:
// list_sample.c
/*
* 演示 list.h 的使用
* 1. 结构体必须包含 struct list_head 成员
* 2. INIT_LIST_HEAD(&studentsList); // 初始化链表头结点
* 3. list_add(&pXiaoMing->list_node, &studentsList); // 链表头部插入
* 4. list_add_tail(&pZero->list_node, &studentsList); // 链表尾部插入
* 5. list_for_each_safe(pos,tmp,listHead) // 对列表进行迭代,以防删除列表条目。
list_for_each_entry(pListEntry, listHead, list_node) // 迭代给定类型的列表,遍历各个条目
list_for_each(pos,listHead) // 对列表进行迭代,一般用 list_for_each_safe
* 6. list_entry(pos,stStudentData,list_node); // 获取当前 struct list_head 的结构体指针
list_entry(studentsList.next,stStudentData,list_node); // 链表第一个结构体指针
list_entry(studentsList.prev,stStudentData,list_node); // 链表最后一个结构体指针
注意:获取结构体指针之前,需要先判断链表是否为空,list_entry在空链表依然可以获取到数据,这显然不是想要的结果
* 7. list_del(pos); // 从列表中删除条目。
* 8. list_empty(list) // 判断空链表
*/
#include <stdio.h>
#include <stdlib.h>
#include "list.h" // 包含 list.h
//#include "my_list.h" // 包含 my_list.h
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
#define list_last_entry(ptr, type, member) \
list_entry((ptr)->prev, type, member)
// 1、定义的结构体必须包含 struct list_head 成员,才可以作为链表结点 2023-09-23 21:30:14
typedef struct studentData
{
int age;
int num;
struct list_head list_node;
char gender[10];
char name[10];
}stStudentData, *pstStudentData;
// 4、遍历链表
void print_list(struct list_head *listHead)
{
struct list_head *pos,*tmp;
pstStudentData pListEntry; // 链表条目 2023-09-23 22:07:14
list_for_each(pos,listHead)
{
pListEntry = list_entry(pos,stStudentData,list_node);
printf("list_for_each: num=%d, name=[%s], gender=[%s], age=%d, \n",
pListEntry->num, pListEntry->name, pListEntry->gender, pListEntry->age);
}
/*
* 对列表进行迭代,以防删除列表条目。
* pos: 要用作循环计数器的&struct list_head。指向迭代的条目的指针;
* tmp: 另一个 &struct list_head, 用作临时存储(外部没作用);
* listHead: 链表头指针 2023-09-23 22:18:11
*/
list_for_each_safe(pos,tmp,listHead)
{
/*
* 获取当前 struct list_head 的结构体指针
* pos: struct list_head指针。
* stStudentData: 包含 struct list_head 的结构体类型名称
* list_node: 结构中 struct list_head 的成员名称。
*/
// 6. 获取当前 struct list_head 的结构体指针
pListEntry = list_entry(pos,stStudentData,list_node);
printf("list_for_each_safe: num=%d, name=[%s], gender=[%s], age=%d, \n",
pListEntry->num, pListEntry->name, pListEntry->gender, pListEntry->age);
}
/*
* 迭代给定类型的列表
* pListEntry: 要用作循环计数器的类型指针
* listHead: 链表头指针 2023-09-23 22:18:11
* list_node: 结构中list_struct的名称。
*/
list_for_each_entry(pListEntry, listHead, list_node)
{
printf("list_for_each_entry: num=%d, name=[%s], gender=[%s], age=%d, \n",
pListEntry->num, pListEntry->name, pListEntry->gender, pListEntry->age);
}
}
void clear_list(struct list_head *listHead)
{
struct list_head *pos,*tmp;
pstStudentData pListEntry; // 链表条目 2023-09-23 22:07:14
list_for_each_safe(pos,tmp,listHead)
{
pListEntry = list_entry(pos,stStudentData,list_node);
printf("del: num=%d, name=[%s], gender=[%s], age=%d, \n",
pListEntry->num, pListEntry->name, pListEntry->gender, pListEntry->age);
/*
* 从列表中删除条目。
* pos: 要从列表中删除的元素。struct list_head *
*/
list_del(pos);
free(pListEntry);
}
}
int main()
{
// 2、定义并初始化头结点
struct list_head studentsList;// 头结点
INIT_LIST_HEAD(&studentsList);
//INIT_LIST_HEAD(NULL);
// 3.1、在链表头部插入数据 list_add
pstStudentData pXiaoMing=(pstStudentData)malloc(sizeof(stStudentData));
pXiaoMing->age = 10;
pXiaoMing->num = 1;
sprintf(pXiaoMing->gender,"%s","boy");
sprintf(pXiaoMing->name,"%s","XiaoMing");
list_add(&pXiaoMing->list_node, &studentsList);
pstStudentData pXiaoHua=(pstStudentData)malloc(sizeof(stStudentData));
pXiaoHua->age = 11;
pXiaoHua->num = 2;
sprintf(pXiaoHua->gender,"%s","girl");
sprintf(pXiaoHua->name,"%s","XiaoHua");
list_add(&pXiaoHua->list_node, &studentsList);
// 3.2、在链表尾部插入数据 list_add_tail
pstStudentData pZero=(pstStudentData)malloc(sizeof(stStudentData));
pZero->age = 8;
pZero->num = 0;
sprintf(pZero->gender,"%s","boy");
sprintf(pZero->name,"%s","zero");
list_add_tail(&pZero->list_node, &studentsList);
// 4、遍历链表
print_list(&studentsList);
// 5.获取结构体数据 2023-09-24 21:18:02
pstStudentData pFirst = list_entry(studentsList.next,stStudentData,list_node);
//pstStudentData pFirst = list_first_entry(&studentsList,stStudentData,list_node);
printf("pFirst: num=%d, name=[%s], gender=[%s], age=%d, \n",
pFirst->num, pFirst->name, pFirst->gender, pFirst->age);
pstStudentData pLast = list_entry(studentsList.prev,stStudentData,list_node);
//pstStudentData pLast = list_last_entry(&studentsList,stStudentData,list_node);
printf("pLast: num=%d, name=[%s], gender=[%s], age=%d, \n",
pLast->num, pLast->name, pLast->gender, pLast->age);
// 6.clear_list
clear_list(&studentsList);
// 7.判断空链表
if(list_empty(&studentsList))
{
pstStudentData pFirst = list_entry(studentsList.next,stStudentData,list_node);
if(pFirst==NULL)
printf("list is empty\n");
else
printf("list is empty,error fist %p\n", pFirst);
}
return 0;
}
四、例子中使用的 list.h 代码
// list.h
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
/*
prefetch(x) attempts to pre-emptively get the memory pointed to
by address "x" into the CPU L1 cache.
prefetch(x) should not cause any kind of exception, prefetch(0) is
specifically ok.
prefetch() should be defined by the architecture, if not, the
#define below provides a no-op define.
There are 3 prefetch() macros:
prefetch(x) - prefetches the cacheline at "x" for read
prefetchw(x) - prefetches the cacheline at "x" for write
spin_lock_prefetch(x) - prefectches the spinlock *x for taking
there is also PREFETCH_STRIDE which is the architecure-prefered
"lookahead" size for prefetching streamed operations.
*/
/*
* These cannot be do{}while(0) macros. See the mental gymnastics in
* the loop macro.
*/
#ifndef ARCH_HAS_PREFETCH
static inline void prefetch(const void *x) {;}
#endif
#ifndef ARCH_HAS_PREFETCHW
static inline void prefetchw(const void *x) {;}
#endif
#ifndef ARCH_HAS_SPINLOCK_PREFETCH
#define spin_lock_prefetch(x) prefetchw(x)
#endif
#ifndef PREFETCH_STRIDE
#define PREFETCH_STRIDE (4*L1_CACHE_BYTES)
#endif
static inline void prefetch_range(void *addr, size_t len)
{
#ifdef ARCH_HAS_PREFETCH
char *cp;
char *end = addr + len;
for (cp = addr; cp < end; cp += PREFETCH_STRIDE)
prefetch(cp);
#endif
}
/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200200)
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *new_node,
struct list_head *prev,
struct list_head *next)
{
next->prev = new_node;
new_node->next = next;
new_node->prev = prev;
prev->next = new_node;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new_node, struct list_head *head)
{
__list_add(new_node, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new_node, struct list_head *head)
{
__list_add(new_node, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
//entry->next = (struct list_head *)LIST_POISON1;
//entry->prev = (struct list_head *)LIST_POISON2;
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_move - delete from one list and add as another's head
* @list: the entry to move
* @head: the head that will precede our entry
*/
static inline void list_move(struct list_head *list, struct list_head *head)
{
__list_del(list->prev, list->next);
list_add(list, head);
}
/**
* list_move_tail - delete from one list and add as another's tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev, list->next);
list_add_tail(list, head);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
/**
* list_empty_careful - tests whether a list is
* empty _and_ checks that no other CPU might be
* in the process of still modifying either member
*
* NOTE: using list_empty_careful() without synchronization
* can only be safe if the only activity that can happen
* to the list entry is list_del_init(). Eg. it cannot be used
* if another CPU could re-list_add() it.
*
* @head: the list to test.
*/
static inline int list_empty_careful(const struct list_head *head)
{
struct list_head *next = head->next;
return (next == head) && (next == head->prev);
}
static inline void __list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
static inline void __list_splice_tail(struct list_head *list,
struct list_head *head)
{
struct list_head *last = list->prev;
struct list_head *first = list->next;
struct list_head *at = head->prev;
head->prev = last;
last->next = head;
first->prev = at;
at->next = first;
}
/**
* list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static inline void list_splice(struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head);
}
static inline void list_splice_tail(struct list_head *list, struct list_head *head)
{
if(!list_empty(list))
__list_splice_tail(list, head);
}
/**
* list_splice_init - join two lists and reinitialise the emptied list.
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* The list at @list is reinitialised
*/
static inline void list_splice_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head);
INIT_LIST_HEAD(list);
}
}
#ifndef offsetof
#define offsetof(type, f) ((size_t) \
((char *)&((type *)0)->f - (char *)(type *)0))
#endif
#ifndef container_of
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr);\
(type *)( (char *)__mptr - offsetof(type,member) );})
#endif
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; prefetch(pos->next), pos != (head); \
pos = pos->next)
/**
* __list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*
* This variant differs from list_for_each() in that it's the
* simplest possible list iteration code, no prefetching is done.
* Use this for code that knows the list to be very short (empty
* or 1 entry) most of the time.
*/
#define __list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* list_for_each_prev - iterate over a list backwards
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
pos = pos->prev)
/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#define get_first_item(attached, type, member) \
((type *)((char *)((attached)->next)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_entry_reverse - iterate backwards over list of given type.
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member); \
prefetch(pos->member.prev), &pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
/**
* list_prepare_entry - prepare a pos entry for use as a start point in
* list_for_each_entry_continue
* @pos: the type * to use as a start point
* @head: the head of the list
* @member: the name of the list_struct within the struct.
*/
#define list_prepare_entry(pos, head, member) \
((pos) ? : list_entry(head, typeof(*pos), member))
/**
* list_for_each_entry_continue - iterate over list of given type
* continuing after existing point
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_continue(pos, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member); \
prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
* list_for_each_entry_safe_continue - iterate over list of given type
* continuing after existing point safe against removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe_continue(pos, n, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/*
* Double linked lists with a single pointer list head.
* Mostly useful for hash tables where the two pointer list head is
* too wasteful.
* You lose the ability to access the tail in O(1).
*/
struct hlist_head {
struct hlist_node *first;
};
struct hlist_node {
struct hlist_node *next, **pprev;
};
#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)
static inline int hlist_unhashed(const struct hlist_node *h)
{
return !h->pprev;
}
static inline int hlist_empty(const struct hlist_head *h)
{
return !h->first;
}
static inline void __hlist_del(struct hlist_node *n)
{
struct hlist_node *next = n->next;
struct hlist_node **pprev = n->pprev;
*pprev = next;
if (next)
next->pprev = pprev;
}
static inline void hlist_del(struct hlist_node *n)
{
__hlist_del(n);
n->next = (struct hlist_node *)LIST_POISON1;
n->pprev = (struct hlist_node **)LIST_POISON2;
}
static inline void hlist_del_init(struct hlist_node *n)
{
if (n->pprev) {
__hlist_del(n);
INIT_HLIST_NODE(n);
}
}
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;
if (first)
first->pprev = &n->next;
h->first = n;
n->pprev = &h->first;
}
/* next must be != NULL */
static inline void hlist_add_before(struct hlist_node *n,
struct hlist_node *next)
{
n->pprev = next->pprev;
n->next = next;
next->pprev = &n->next;
*(n->pprev) = n;
}
static inline void hlist_add_after(struct hlist_node *n,
struct hlist_node *next)
{
next->next = n->next;
n->next = next;
next->pprev = &n->next;
if(next->next)
next->next->pprev = &next->next;
}
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define hlist_for_each(pos, head) \
for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
pos = pos->next)
#define hlist_for_each_safe(pos, n, head) \
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
pos = n)
/**
* hlist_for_each_entry - iterate over list of given type
* @tpos: the type * to use as a loop counter.
* @pos: the &struct hlist_node to use as a loop counter.
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry(tpos, pos, head, member) \
for (pos = (head)->first; \
pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
* @tpos: the type * to use as a loop counter.
* @pos: the &struct hlist_node to use as a loop counter.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_continue(tpos, pos, member) \
for (pos = (pos)->next; \
pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_from - iterate over a hlist continuing from existing point
* @tpos: the type * to use as a loop counter.
* @pos: the &struct hlist_node to use as a loop counter.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_from(tpos, pos, member) \
for (; pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @tpos: the type * to use as a loop counter.
* @pos: the &struct hlist_node to use as a loop counter.
* @n: another &struct hlist_node to use as temporary storage
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
for (pos = (head)->first; \
pos && ({ n = pos->next; 1; }) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = n)
#endif
五、抽取常用函数组成的简约版list.h —— my_list.h
// my_list.h 2023-09-24 23:07:43
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
struct list_head {
struct list_head *next, *prev;
};
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *new_node,
struct list_head *prev,
struct list_head *next)
{
next->prev = new_node;
new_node->next = next;
new_node->prev = prev;
prev->next = new_node;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new_node, struct list_head *head)
{
__list_add(new_node, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new_node, struct list_head *head)
{
__list_add(new_node, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
//entry->next = (struct list_head *)LIST_POISON1;
//entry->prev = (struct list_head *)LIST_POISON2;
}
#ifndef offsetof
#define offsetof(type, f) ((size_t) \
((char *)&((type *)0)->f - (char *)(type *)0))
#endif
#ifndef container_of
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr);\
(type *)( (char *)__mptr - offsetof(type,member) );})
#endif
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
#ifndef ARCH_HAS_PREFETCH
static inline void prefetch(const void *x) {;}
#endif
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; prefetch(pos->next), pos != (head); \
pos = pos->next)
/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#endif //_LINUX_LIST_H
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁