我正在学习如何使用list.h.中的内核链接列表API
我了解到,在使用list_del()
而不是使用list_for_each()
删除节点时,需要使用list_for_each_safe()
。
list_for_each_safe()
:的代码
#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()
:的代码
for (pos = (head)->next; pos != (head); pos = pos->next)
我注意到它们都非常相似,只是_safe
版本需要一个额外的参数来用作"临时存储"(如这里所述,list.h)
我知道何时正确应用该函数,_safe
版本用于删除,正常版本用于访问,但我很好奇额外的参数是如何使其"安全"的?
考虑以下内容,其中我使用list_for_each_safe()
:删除链接列表中的每个节点
struct kool_list{
int to;
struct list_head list;
int from;
};
struct kool_list *tmp;
struct list_head *pos, *q;
struct kool_list mylist;
list_for_each_safe(pos, q, &mylist.list){
tmp= list_entry(pos, struct kool_list, list);
printf("freeing item to= %d from= %dn", tmp->to, tmp->from);
list_del(pos);
free(tmp);
}
给予q
如何帮助删除?
谢谢你的帮助!
list_del
在内部修改pos
字段的值。在您的示例中,循环体甚至释放了pos
占用的内存。假设您将使用不安全版本的循环:
for (pos = (head)->next; pos != (head); pos = pos->next)
在执行循环体之后,pos
指针变为无效,破坏了增量表达式:pos = pos->next
。
相反,安全foreach将pos->next
的值预先保存在一个临时变量中,然后引用后者,而不是去引用pos
:
for (pos = (head)->next, n = pos->next; pos != (head);
pos = n, n = pos->next)
pos = start;
del(pos);
pos = pos->next;
与相反
pos = start;
n = pos->next;
del(pos);
pos = n;
如果del()是free()和memset(),则pos->next是未定义的