为什么我们需要list_for_each_safe()来删除内核链表中的节点?

发布于 2025-01-04 15:35:17 字数 1331 浏览 1 评论 0原文

我正在学习如何使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小女人ら 2025-01-11 15:35:17

这是必要的,因为 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)

That is necessary because list_del internally modifies the value of pos fields. In your example the loop body even frees the memory occupied by pos. Suppose that you would use unsafe version of the loop:

for (pos = (head)->next; pos != (head); pos = pos->next)

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 dereferencing pos:

for (pos = (head)->next, n = pos->next; pos != (head); \
    pos = n, n = pos->next)
唔猫 2025-01-11 15:35:17
pos = start;
del(pos);
pos = pos->next;

与 if del() is free() 和 memset() 相反

pos = start;
n = pos->next;
del(pos);
pos = n;

, pos->next 是未定义的

pos = start;
del(pos);
pos = pos->next;

as opposed to

pos = start;
n = pos->next;
del(pos);
pos = n;

if del() is free() and memset(), pos->next is undefined

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文