list 解释 list_for_each_entry 和 list_for_each_entry_safe
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16230524/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Explain list_for_each_entry and list_for_each_entry_safe
提问by goodies
Can anyone explain the working of list_for_each_entry and ...entry_safe loop in linux. It is like
谁能解释 linux 中 list_for_each_entry 和 ...entry_safe 循环的工作原理。它像是
list_for_each_entry(type *cursor, struct list_head *list, member)
list_for_each_entry(type *cursor, struct list_head *list, member)
list_for_each_entry_safe(type *cursor, type *next, struct list_head *list,member)
list_for_each_entry_safe(type *cursor, type *next, struct list_head *list,member)
What are the role of all these parameters and how they are used to traverse the list.
所有这些参数的作用是什么以及它们如何用于遍历列表。
Thanks in ADVANCE
提前致谢
采纳答案by Daniel Santos
EDIT: sorry, it must be late, I've made a lot of typos.
编辑:对不起,一定是晚了,我打错了很多字。
They are pure fun! :) The difference is that list_for_each_entry
will break if you delete something while iterating the list and list_for_each_entry_safe
won't (of course, at the expense of some extra CPU instructions).
他们是纯粹的乐趣!:) 不同之处在于,list_for_each_entry
如果您在迭代列表时删除某些内容,则不会中断list_for_each_entry_safe
(当然,以一些额外的 CPU 指令为代价)。
The kernel has settled on doubly-linked lists (which I'm presuming you understand), although there is a singingly linked list implementation in list.h. Your list is just:
内核已经确定了双向链表(我假设你理解),尽管在 list.h 中有一个唱歌的链表实现。您的清单只是:
struct list_head {
struct list_head *next;
struct list_head *prev;
};
Note that the same struct is used for both the "head" of the list as well as each node. When the list is empty, the head's next
and prev
members just point to the head its self. Thus, iterating the list is just a process of starting with the head's next
member and calling that a node, unless it's the same address as prev
(when you stop). Otherwise, your for
body is invoked and you can use the container_of()
macro to get a pointer to your actual struct and play with it. Then, in the 3rd field of the for
, we just just move to the next next
.
请注意,列表的“头”和每个节点都使用相同的结构。当列表为空时,头部next
和prev
成员只指向头部自身。因此,迭代列表只是从头的next
成员开始并将其称为节点的过程,除非它的地址与prev
(当您停止时)相同。否则,您的for
主体将被调用,您可以使用container_of()
宏获取指向实际结构的指针并使用它。然后,在 的第三个字段中for
,我们只是移动到下一个next
。
EDIT: whoops, I apologize, you asked for an explanation of the parameters. Well, I would check it out directly if I were you rather than taking somebody's word for it. For those, I would suggest the Kernel API docsthemselves, which at least exist for the linked list library. I'm trying to get a patch set through that will add them for the red-black tree library as well, but getting stuff through can be quite a process.
编辑:哎呀,我很抱歉,您要求对参数进行解释。好吧,如果我是你,我会直接检查它而不是相信某人的话。对于那些,我会建议内核 API 文档本身,它至少存在于链接列表库中。我正在尝试获取一个补丁集,该补丁集也将为红黑树库添加它们,但是获取内容可能是一个相当大的过程。
Also of note: http://kernelnewbies.org/FAQ/LinkedLists
另请注意:http: //kernelnewbies.org/FAQ/LinkedLists
Here's a quick example:
这是一个快速示例:
struct list_head my_actual_list;
struct my_struct {
struct list_head node;
/* some other members */
};
/* in a function body somewhere... */
struct list_head *i;
list_for_each(i, &my_actual_list) {
struct my_struct *obj = list_entry(i, struct my_struct, node);
// do something with obj
}
list_entry
is just an alias for container_of
list_entry
只是一个别名 container_of
EDIT #2
编辑#2
OK, so in answer to your question in comments, I'm going to just expand my answer. I can actually appreciate the difficulty in grasping this concept as it does have a few strange things in it compared to C++ STL containers, C arrays, etc, but once you are accustom to the idioms, it will seem quite natural. Still in the future, I really urge you to start looking at the definition for these structs, functions & macros yourself and trying to piece together an understanding, then ask the questions.
好的,所以为了在评论中回答您的问题,我将扩大我的答案。我实际上可以理解掌握这个概念的难度,因为与 C++ STL 容器、C 数组等相比,它确实有一些奇怪的东西,但是一旦你习惯了这些习语,它就会显得很自然。在未来,我真的敦促您开始自己查看这些结构、函数和宏的定义,并尝试拼凑出一个理解,然后提出问题。
So first off, each node in your list is a struct that contains a member of type struct list_head
and the list its selfis of type struct list_head
. Thus, who is the container and who is the contained in this case, simply depends upon how they are used, but typically, it will be expressed in the names these members are given. The type of the iterator is struct list_head *
. Here's an example and I'll replace the normal function & macro calls with their equivalent code:
因此,首先,列表中的每个节点都是一个结构体,其中包含一个 type 成员,struct list_head
而列表本身的类型为 type struct list_head
。因此,在这种情况下,谁是容器,谁是被包含者,仅取决于它们的使用方式,但通常会以这些成员的名称来表示。迭代器的类型是struct list_head *
。这是一个示例,我将用它们的等效代码替换正常的函数和宏调用:
struct my_container {
struct list_head list;
int some_member;
/* etc. */
};
struct my_obj {
struct list_head node;
int some_member;
/* etc. */
};
void func() {
struct my_container container;
struct my_obj obj1, obj2;
struct list_head *i;
/* INIT_LIST_HEAD(&container.list); */
container.list.next = &container.list;
container.list.prev = &container.list;
/* list_add_tail(&obj1.node); */
container.list.prev = &obj1.node;
obj1.node.next = &container.list;
obj1.node.prev = &container.list;
container.list.next = &obj1.node;
/* list_add_tail(&obj2.node); */
container.list.prev = &obj2.node;
obj2.node.next = &container.list;
obj2.node.prev = &obj1.node;
obj1.node.next = &obj2.node;
/* list_for_each(i, &container.list) { */
for (i = container.list.next; i != &container.list; i = i->next) {
struct my_obj *obj = list_entry(i, struct my_obj, node);
/* do stuff */
}
}