概述
分析的结果:
1.list_for_each和list_for_each_entry都是遍历链表的两个宏,本质上都是for循环。
2.他们做的事情本质上都一样,A.获取链表头,B.判断链表项是不是链表头,C.指向链表的下一项。
3.他们的区别:list_for_each遍历的链表,其链表项不属于某个结构体。或者说不关心它是不是包含在某个结构体中。
list_for_each_entry遍历的链表,其每一项都是某个结构体中的成员,单纯遍历链表还不行,还要找到包含这个
链表项的结构体的地址,从而为下一步应用该结构体做好准备。
/*******************************************************************************************************************************/
/***********************内核重要链表操作函数:list_for_each的源码分析***********************************************************/
/*******************************************************************************************************************************/
list_for_each内核中的定义:
/**
* list_for_each
-
iterate over a list
* @pos:
the &struct list_head to use as a loop cursor.
* @head:
the head for your list.
*/
#define list_for_each(pos, head)
for (pos = (head)->next; pos != (head); pos = pos->next)
/*
*对list_for_each的理解:
*1.首先看内核中的注释:iterate over a list,翻译为中文就是遍历链表,@pos:
the &struct list_head to use as a loop cursor.翻译:
*结构体list_head使用的循环游标。@head:
the head for your list.翻译:链表头
*2.看源码:#define list_for_each(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next)
*就是一个简单的for循环。循环的初始化工作:pos指向链表头的下一项。循环的条件:pos不是链表头。每次循环要做的事情:pos指向链表中的下一项
*3.总结。这个段代码还是很好理解的,list_for_each 会被替换为一个for循环,用于遍历一个链表。
*/
/*******************************************************************************************************************************/
/***********************内核重要链表操作函数:list_entry***的源码分析***********************************************************/
/*******************************************************************************************************************************/
list_entry内核源码:
/**
* list_entry - get the struct for this entry
* @ptr:
the &struct list_head pointer.
* @type:
the type of the struct this is embedded in.
* @member:
the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member)
container_of(ptr, type, member)
/*
*1.内核注释:list_entry - get the struct for this entry,翻译:获得这一项的结构体
*@ptr:
the &struct list_head pointer.
翻译:
*2.从源码中看:list_entry就是container_of,因此搞懂container_of就搞懂了list_entry.看下面的container_of的解析
*/
/*******************************************************************************************************************************/
/***********************内核重要链表操作函数:container_of的源码分析************************************************************/
/*******************************************************************************************************************************/
container_of内核中的源码:
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({
const typeof(((type *)0)->member)*__mptr = (ptr);
(type *)((char *)__mptr - offsetof(type, member)); })
/*
*1.内核中的注释:container_of - cast a member of a structure out to the containing structure,翻译:通过某个结构体成员计算出包含它的结构体
*@ptr: the pointer to the member.翻译:结构体成员指针
*@type: the type of the container struct this is embedded in,翻译:包含着给定成员的结构体的类型
*@member: the name of the member within the struct.翻译:给定成员的名字
*2.源码分析:#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
*这个宏,核心代码:((size_t) &((TYPE *)0)->MEMBER),这样理解:有个type*的结构体,地址为0,它指向member成员,
*此时member成员的地址就是member在结构体中的偏移。因此,这个宏叫offsetof,即...的偏移
*然后分析:
*#define container_of(ptr, type, member) ({
*
const typeof(((type *)0)->member)*__mptr = (ptr);
*
(type *)((char *)__mptr - offsetof(type, member)); })
*这个宏的核心代码是:({const typeof(((type *)0)->member)*__mptr = (ptr);(type *)((char *)__mptr - offsetof(type, member));})这个代码块
*2.1第一句:const typeof(((type *)0)->member)*__mptr = (ptr),定义了__mptr指针,指针类型为 const typeof((type *)0)->member)
*typeof((type *)0)->member)就是获取member的类型,因此:第一句定义了一个和member类型一样的指针。并且指向了ptr
*2.2第二句:(type *)((char *)__mptr - offsetof(type, member))
*第一句理解了,第二句就很好理解了。__mptr的地址就是传入的ptr的地址。这个地址减去member在包含它的结构体中的偏移,不就是包含它的结构体的地址吗?
*因此,第二句的意思就是通过给定的结构体某个成员的地址,算出该成员在结构体中的偏移,然后用改地址减去该偏移,从而得到包含它的结构体的地址。
*/
/*******************************************************************************************************************************/
/***********************内核重要链表操作函数:list_for_each_entry的源码分析*****************************************************/
/*******************************************************************************************************************************/
list_for_each_entry在内核中的定义:
/**
* list_for_each_entry
-
iterate over list of given type
* @pos:
the type * to use as a loop cursor.
* @head:
the head for your list.
* @member:
the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member)
for (pos = list_entry((head)->next, typeof(*pos), member);
&pos->member != (head);
pos = list_entry(pos->member.next, typeof(*pos), member))
/*
*1.首先看内核中的注释:遍历给定类型列表,这里就和list_for_each不同了,list_for_each是遍历一个链表。
*@pos:
the type * to use as a loop cursor.翻译:作为循环游标的类型
*@head:
the head for your list.
翻译:链表头
*@member:
the name of the list_struct within the struct. 翻译:结构体中的链表结构体的名字
*2.看源码:也是一个for循环。
*2.1初始化工作:调用list_entry,list_entry就是container_of,container_of上面已经分析,就是通过成员地址计算出包含该成员的结构体地址
*因此,初始化工作,找到给定成员构造的链表中第一项的的接头体地址并赋值给pos.
*2.2循环执行的条件:链表项不是链表头
*2.3循环每次都要做的事情。pos指向给定链表下一项的被包含的结构体的地址。
*总结:list_for_each_entry也是用来遍历链表的,只不过这个链表有点特使,构成链表的每一项是更高一级结构体中的某一项
*/
最后
以上就是舒适过客为你收集整理的list_for_each与list_for_each_entry的全部内容,希望文章能够帮你解决list_for_each与list_for_each_entry所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复