【数据结构】list.h 详细使用教程 -- 附带例子代码

news2024/12/27 10:54:06

目录

  • 一、概述
  • 二、详细使用步骤
    • ✨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 的使用步骤,基本步骤有下面几个:

    1. 定义结构体时必须包含 struct list_head 成员
    1. 初始化链表头结点:
      INIT_LIST_HEAD(&studentsList);
    1. 添加结点:
      list_add(&pXiaoMing->list_node, &studentsList); // 链表头部插入
      list_add_tail(&pZero->list_node, &studentsList); // 链表尾部插入
    1. 遍历链表:
      list_for_each_safe(pos,tmp,listHead) // 对列表进行迭代,以防删除列表条目。
      list_for_each_entry(pListEntry, listHead, list_node) // 迭代给定类型的列表,遍历各个条目
      list_for_each(pos,listHead) // 对列表进行迭代,一般用 list_for_each_safe
    1. 获取结构体数据:
      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在空链表依然可以获取到数据,这显然不是想要的结果
    1. 删除结点
      list_del(pos); // 从列表中删除条目。
    1. 判断是否空链表
      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

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1038123.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java double类型 向上取整,向下取整,四舍五入

向上取整&#xff1a;Math.ceil(double a) 向下取整&#xff1a;Math.floor(double a) 四舍五入取整&#xff1a;Math.round(double a) 直接取整数&#xff1a;intValue() public static void main(String[] args) {Double number 5.3;Double number1 5.8;//向上取整Doubl…

UE5 虚幻引擎 如何使用构造脚本(Construction Script)? 构造脚本的奥秘!

目录 1 构造脚本&#xff08;Construction Script&#xff09;1.1 介绍1.2 案例1&#xff1a;利用样条组件程序化生成树木1.2 案例2&#xff1a;利用样条组件和样条网格体组件程序化生成道路 1 构造脚本&#xff08;Construction Script&#xff09; 1.1 介绍 问题&#xff1a…

leetcode top100(20) 搜索二维矩阵 II

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,2…

腾讯mini项目-【指标监控服务重构】2023-08-24

今日已办 Jeager 功能 监控分布式工作流程并排除故障识别性能瓶颈追踪根本原因分析服务依赖关系 部署 部署 Deployment — Jaeger documentation (jaegertracing.io) 支持 clickhouse jaegertracing/jaeger-clickhouse: Jaeger ClickHouse storage plugin implementation …

Java8实战-总结34

Java8实战-总结34 重构、测试和调试使用 Lambda 重构面向对象的设计模式观察者模式责任链模式 重构、测试和调试 使用 Lambda 重构面向对象的设计模式 观察者模式 观察者模式是一种比较常见的方案&#xff0c;某些事件发生时&#xff08;比如状态转变&#xff09;&#xff0…

Java之转换流的详细解析

2. 转换流 2.1 字符编码和字符集 字符编码 计算机中储存的信息都是用二进制数表示的&#xff0c;而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。按照某种规则&#xff0c;将字符存储到计算机中&#xff0c;称为编码 。反之&#xff0c;将…

docker容器安装MongoDB数据库

一&#xff1a;MongoDB数据库 1.1 简介 MongoDB是一个开源、高性能、无模式的文档型数据库&#xff0c;当初的设计就是用于简化开发和方便扩展&#xff0c;是NoSQL数据库产品中的一种。是最 像关系型数据库&#xff08;MySQL&#xff09;的非关系型数据库。 它支持的数据结构…

封装一个高级查询组件

封装一个高级查询组件 背景一&#xff0c;前端相关代码二&#xff0c;后端相关代码三&#xff0c;呈现效果总结 背景 业务有个按照自定义选择组合查询条件&#xff0c;保存下来每次查询的时候使用的需求。查了一下项目里的代码没有现成的组件可以用&#xff0c;于是封装了一个 …

腾讯mini项目-【指标监控服务重构】2023-08-29

今日已办 Collector 指标聚合 由于没有找到 Prometheus 官方提供的可以聚合指定时间区间内的聚合函数&#xff0c;所以自己对接Prometheus的api来聚合指定容器的cpu_avg、cpu_99th、mem_avg 实现成功后对接小组成员测试完提供的时间序列和相关容器&#xff0c;将数据记录在表格…

相机One Shot标定

1 原理说明 原理部分网上其他文章[1][2]也已经说的比较明白了&#xff0c;这里不再赘述。 2 总体流程 参考论文作者开源的Matlab代码[3]和github上的C代码[4]进行说明&#xff08;不得不说还是Matlab代码更优雅&#xff09; 论文方法总体分两部&#xff0c;第一部是在画面中找…

李宏毅hw-9:Explainable ML

——欲速则不达&#xff0c;我已经很幸运了&#xff0c;只要珍惜这份幸运就好了&#xff0c;不必患得患失&#xff0c;慢慢来。 ----查漏补缺&#xff1a; 1.关于这个os.listdir的使用 2.从‘num_文件名.jpg’中提取出数值&#xff1a; 3.slic图像分割标记函数的作用&#xf…

【音视频流媒体】4、摄像头:分辨率、光圈|快门|感光度、焦距

文章目录 一、摄像头分辨率二、光圈、快门、感光度2.1 光圈2.1.1 外观2.1.2 光圈在相机中如何表示的2.1.3 对拍照的影响2.1.4 如何选择合适的光圈2.1.5 光圈在相机中如何设置 2.2 快门2.2.1 外观2.2.2 快门在相机中的表示2.2.3 快门对于拍照有什么影响2.2.4 选择合适的快门2.2.…

【C#】.Net基础语法一

目录 一、程序集信息 【1.1】Properties中AssemblyInfo文件 二、.Net程序的两次编译过程 三、.Net中命名空间和类 【3.1】引入命名空间 【3.2】修改默认的命名空间 【3.3】命名空间的总结 四、.Net中数据类型 【4.1】数值型 【4.2】非数值型 五、.Net中变量 【5.1】…

Selenium WebUI 自动化测试框架

框架结构 框架结构 框架基于 PO 模型进行设计&#xff0c;将页面元素与操作进行拆分&#xff0c;减少页面改动时的维护成本&#xff1b;同时使用 xsd 自定义 xml 标签&#xff0c;通过解析 xml 来驱动 selenium 进行执行&#xff0c;减少了一定的语言学习成本。 主要功能 基于…

[架构之路-221]:鸿蒙系统和安卓系统的比较:微内核VS宏内核, 分布式VS单体式

目录 一、鸿蒙系统和安卓系统的系统架构 1.1 鸿蒙系统的分层架构 1.2 安卓系统的分层架构 1.3 鸿蒙系统和安卓系统是操作系统吗&#xff1f; 二、鸿蒙系统和安卓系统的系统架构比较 2.1 它们与Linux操作系统的关系 2.2 架构比较 三、操作系统基础 3.1 微内核架构 3.2…

leetcode刷题 二维数组 八方向

题目描述 输入&#xff1a;board [[0,1,0],[0,0,1],[1,1,1],[0,0,0]] 输出&#xff1a;[[0,0,0],[1,0,1],[0,1,1],[0,1,0]] 题目分析:就是以二维数组某个元素为中心&#xff0c;寻找周围八个方向的元素&#xff0c;按照题目要求修改二维数组元素返回&#xff1b; 拷贝一份二…

FPGA板卡启动以及LED灯带调试

环境配置 软件&#xff1a; MobaXterm&#xff08;free版本即可&#xff09;下载教程参考&#xff1a; MobaXterm&#xff08;终端工具&#xff09;下载&安装&使用教程_蜗牛也不慢......的博客-CSDN博客 Win32 Disklmager 下载教程参考&#xff1a; 不分类工具&am…

Nature Communications | 张阳课题组:端到端深度学习实现高精度RNA结构预测

RNA分子是基因转录的主要执行者&#xff0c;也是细胞运作的隐形功臣。它们在基因表达调控、支架构建以及催化活性等多个生命过程中都扮演着关键角色。虽然RNA如此重要&#xff0c;但由于实验数据的缺乏&#xff0c;准确预测RNA 的三维空间结构仍然是目前计算生物学面临的重大挑…

HDMI之HDCP 2.3

Authentication and Key Exchange Without Stored Km With Stored Km HDCP2Version DDC时序 协议截图 Bit2为1,可知DUT设备支持HDCP 2.2及以上版本 RxStatus DDC时序 协议截图 <

C++ 类、方法的同一声明不同实现的方式

问题提出 头文件&#xff1a;声明CurrentTime类和PrintTime方法。 #ifndef CURRENT_TIME_H #define CURRENT_TIME_H class CurrentTime { public:void PrintTime(); }; #endifmain函数&#xff1a;创建CurrentTime对象&#xff0c;调用PrintTime。 #include "current_t…