为什么我们需要list_for_each_safe()来删除内核链表中的节点?
我正在学习如何使用 list.h 中的内核链表 API。
我了解到,在使用 list_del()
删除节点时需要使用 list_for_each_safe()
,而不是使用 list_for_each()
。
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= %d\n", tmp->to, tmp->from);
list_del(pos);
free(tmp);
}
给出 q
如何帮助删除?
感谢您的帮助!
I'm learning how to use the kernel linked-list API from list.h.
I learned that I need to use list_for_each_safe()
when deleting nodes off with list_del()
instead of using list_for_each()
.
Code for 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)
Code for list_for_each()
:
for (pos = (head)->next; pos != (head); pos = pos->next)
I notice they both are very similar except that the _safe
version takes an extra argument to be used as 'temporary storage' (stated here, list.h).
I understand when to apply the function correcly, _safe
version for deleting, normal version for accessing, but I'm curious how the extra argument made it 'safe'?
Consider the following, where I'm deleting every node in a linked list using 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= %d\n", tmp->to, tmp->from);
list_del(pos);
free(tmp);
}
How does giving q
help in deleting?
Thanks for any help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是必要的,因为
list_del
在内部修改pos
字段的值。在您的示例中,循环体甚至释放了 pos 占用的内存。假设您将使用循环的不安全版本:执行循环体后,
pos
指针变得无效,破坏增量表达式:pos = pos->next
。相反,安全 foreach 将 pos->next 的值预先保存在临时变量中,然后引用后者而不是取消引用 pos:
That is necessary because
list_del
internally modifies the value ofpos
fields. In your example the loop body even frees the memory occupied bypos
. Suppose that you would use unsafe version of the loop:After executing the loop body
pos
pointer becomes invalid breaking the increment expression:pos = pos->next
.As opposite, the safe foreach pre-saves the value of
pos->next
in a temporary variable and then refers to the latter instead of dereferencingpos
:与 if del() is free() 和 memset() 相反
, pos->next 是未定义的
as opposed to
if del() is free() and memset(), pos->next is undefined