说明list_for_each_entry和list_for_each_entry_safe [英] Explain list_for_each_entry and list_for_each_entry_safe
问题描述
谁能解释Linux中list_for_each_entry和... entry_safe循环的工作. 就像
Can anyone explain the working of list_for_each_entry and ...entry_safe loop in linux. It is like
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)
所有这些参数的作用是什么,以及如何使用它们遍历列表.
What are the role of all these parameters and how they are used to traverse the list.
非常感谢
推荐答案
对不起,一定要迟到了,我犯了很多错字.
sorry, it must be late, I've made a lot of typos.
它们真有趣! :)区别在于,如果在迭代列表时删除某些内容,list_for_each_entry
将会中断,而list_for_each_entry_safe
不会中断(当然,这要花一些额外的CPU指令).
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.h中有一个严格的链表实现,但内核已经确定了双链表(我想您理解了).您的清单是:
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:
struct list_head {
struct list_head *next;
struct list_head *prev;
};
请注意,列表的头"和每个节点都使用相同的结构.当列表为空时,标头的next
和prev
成员仅指向标头自身.因此,迭代列表只是从头的next
成员开始并调用该节点的过程,除非它与prev
是相同的地址(停止时).否则,将调用for
主体,并且可以使用container_of()
宏获取指向实际结构的指针并对其进行处理.然后,在for
的第3个字段中,我们只是移至下一个next
.
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
.
抱歉,您要求提供有关参数的说明.好吧,如果我是您,我会直接检查出来,而不是相信别人.对于这些,我建议自己使用内核API文档 ,至少在链表列表库中存在.我正在尝试获得一个补丁集,该补丁集也将它们添加到红黑树库中,但是要完成任务可能是一个相当大的过程.
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 docs themselves, 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.
还要注意: http://kernelnewbies.org/FAQ/LinkedLists
这是一个简单的例子:
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
只是container_of
编辑#2
好的,因此,在评论中回答您的问题时,我将扩大答案.我确实可以体会到难以理解这个概念的困难,因为与C ++ STL容器,C数组等相比,它确实有一些奇怪的东西,但是一旦您习惯了这些习惯用法,它就会显得很自然.仍然在将来,我真的敦促您开始研究这些结构,功能和功能的定义.自己建立宏并尝试加深理解,然后提出问题.
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.
因此,首先,列表中的每个节点都是一个结构,其中包含类型为struct list_head
的成员,列表 其自身 的类型为struct list_head
.因此,在这种情况下,谁是容器,谁是容器,仅取决于如何使用它们,但是通常,将使用给定这些成员的名称来表示它.迭代器的类型为struct list_head *
.这是一个示例,我将替换常规功能&宏调用及其等效代码:
So first off, each node in your list is a struct that contains a member of type struct list_head
and the list its self is 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:
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 */
}
}
这篇关于说明list_for_each_entry和list_for_each_entry_safe的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!