在之前的文章《深入理解Linux内核之链表 list.h 功能实现原理、接口说明及示例代码》中详细的分析了链表的各种操作,我们经常使用的操作是“初始化”、“ 添加节点”、“遍历”、“删除”,对于链表节点的删除,使用的相对少,而且由于 删除操作的 宏函数 定义的复杂,容易混淆,本文基于此,对 链表的删除清空做下备忘录。
以单向链表结构 为例,用到的宏函数有2个,分别为:
/*
* Iterate over list of given type safe against removal of list entry.
*
* @param[in] queue the head for your list.
* @param[in] tmp the type * to use as a temp.
* @param[in] node the type * to use as a loop cursor.
* @param[in] type the type of the struct this is embedded in.
* @param[in] member the name of the slist_t within the struct.
*/
#define slist_for_each_entry_safe(queue, tmp, node, type, member) \
for (node = container_of((queue)->next, type, member), \
tmp = (queue)->next ? (queue)->next->next : NULL; \
&node->member; \
node = container_of(tmp, type, member), tmp = tmp ? tmp->next : tmp)
/* 节点删除 */
static inline void slist_del(slist_t *node, slist_t *head)
{
while (head->next) {
if (head->next == node) {
head->next = node->next;
break;
}
head = head->next;
}
}
其中 slist_for_each_entry_safe 中包含了 “safe” ,含义是 “安全”, 专用于 链表删除 的 遍历动作。这个函数的参数类型容易有歧义,这里我们做下 解释:
/*
* Iterate over list of given type safe against removal of list entry.
*
* @param[in] queue 链表 头 head 指针, 是一个指针
* @param[in] tmp struct slist_s * 类型的 临时指针变量
* @param[in] node 我们自己的 链表结构 节点 指针,.
* @param[in] type 我们自己定义的 链表结构体类型, 必须要包含 struct slist_s list 成员.
* @param[in] member 我们自己定义的 链表结构体类型 中的 list 成员
*/
#define slist_for_each_entry_safe(queue, tmp, node, type, member)
而 slist_del(slist_t *node, slist_t *head) 的参数解释如下:
/*
* Iterate over list of given type safe against removal of list entry.
*
* @param[in] node struct slist_s * 类型的 节点变量,是一个指针
* @param[in] head 链表 头 head 指针, 是一个指针
*/
static inline void slist_del(slist_t *node, slist_t *head)
删除并释放 所有链表节点的 程序案例:
/* 自定义的 链表结构体*/
typedef struct{
int id;
int a;
int b;
struct slist_s list;
} usr_list_info_t;
/*--------------- 删除整个链表的伪操作 ---------------*/
struct slist_s *head = get_usr_list_head();
struct slist_s *tmp = NULL;
usr_list_info_t *node = NULL;
slist_for_each_entry_safe(head, tmp, node, usr_list_info_t, list){
slist_del(&(node->list), head);
free(node);
}
如果想删除某一个节点,也是上面的套路,只不过在遍历所有的节点同时,判断当前节点是否是我们想要删除的节点,如果是,则删除,不是则接着遍历。