linux 的list_for_each_entry

linux的宏定义提高了代码的简洁性,但有时候的命名不够完美。比如list_for_each_entry,看名字只知道是遍历list,但一看里面的三个变量参数,有点懵逼。

/**

* 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_head within the struct.

*/

#define list_for_each_entry(pos, head, member) \

for (pos = list_first_entry(head, typeof(*pos), member); \

!list_entry_is_head(pos, head, member); \

pos = list_next_entry(pos, member))

谁是given type? 被遍历的是谁?咋看看不出来。

/**

* list_first_entry - get the first element from a list

* @ptr: the list head to take the element from.

* @type: the type of the struct this is embedded in.

* @member: the name of the list_head within the struct.

*

* Note, that list is expected to be not empty.

*/

#define list_first_entry(ptr, type, member) \

list_entry((ptr)->next, type, member)

这个宏的comments解释说是获取一个list的第一个元素。 但是一看宏定义有点懵,怎么又来一个宏在里面?

/**

* 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_head within the struct.

*/

#define list_entry(ptr, type, member) \

container_of(ptr, type, member)

这个宏定义看解释是获取当前entry的所属结构体,又来一个宏:

  1. /**

  2. * container_of - cast a member of a structure out to the containing structure

  3. * @ptr: the pointer to the member.

  4. * @type: the type of the container struct this is embedded in.

  5. * @member: the name of the member within the struct.

  6. *

  7. * WARNING: any const qualifier of @ptr is lost.

  8. */

  9. #define container_of(ptr, type, member) ({ \

  10. void *__mptr = (void *)(ptr); \

  11. static_assert(__same_type(*(ptr), ((type *)0)->member) || \

  12. __same_type(*(ptr), void), \

  13. "pointer type mismatch in container_of()"); \

  14. ((type *)(__mptr - offsetof(type, member))); })

此宏就是,给了一个结构体变量的其中成员变量,而获取此结构体变量的地址。ptr是成员变量地址,type是结构体类型,member是成员变量在结构体声明里的名字称谓。

所以说 list_entry 是获取ptr所属的结构体地址。list_first_entry 是获取(ptr)->next 所在结构体的地址,

而list_for_each_entry里面还有宏:

/**

* list_entry_is_head - test if the entry points to the head of the list

* @pos: the type * to cursor

* @head: the head for your list.

* @member: the name of the list_head within the struct.

*/

#define list_entry_is_head(pos, head, member) \

(&pos->member == (head))

这个宏名字取的更敷衍。解释内容说是为了验证是不是list的头指针。 看代码是验证pos这个结构体的成员member地址是不是和head一样。

再看另外一个宏:

/**

* list_next_entry - get the next element in list

* @pos: the type * to cursor

* @member: the name of the list_head within the struct.

*/

#define list_next_entry(pos, member) \

list_entry((pos)->member.next, typeof(*(pos)), member)

解释内容说是获取list的下一个成员指针,看代码是获取(pos)->member.next 所在结构体的地址。

这样整体来看:

#define list_for_each_entry(pos, head, member) \

for (pos = list_first_entry(head, typeof(*pos), member); \ //获取head->next所在结构体地址给pos

!list_entry_is_head(pos, head, member); \//判断pos的member成员地址是否和head一样,如果一样,就跳出循环

pos = list_next_entry(pos, member)) //获取(pos)->member.next 所在结构体的地址

综上所述,这里遍历了一个循环链表,表头是head,但是似乎head没被拿来遍历到?直接从head->next开始的?遍历到再次碰到head的地址就结束了,即表明遍历了一圈了。 member就是链表个成员(链表类型地址)内含的内容地址。这里head为什么是废弃的?

相关推荐
qeen875 小时前
【数据结构】建堆的时间复杂度讨论与TOP-K问题
c语言·数据结构·c++·学习·
图码5 小时前
如何用多种方法判断字符串是否为回文?
开发语言·数据结构·c++·算法·阿里云·线性回归·数字雕刻
我星期八休息6 小时前
IT疑难杂症诊疗室:AI时代工程师Superpowers进化论
linux·开发语言·数据结构·人工智能·python·散列表
漂流瓶jz6 小时前
UVA-1152 和为0的4个值 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·二分查找·题解·aoapc·算法竞赛入门经典·uva
你撅嘴真丑6 小时前
map 与 set容器的应用--话题焦点人物
数据结构
生成论实验室7 小时前
《事件关系阴阳博弈动力学:识势应势之道》第二篇:阴阳博弈——认知的动力学基础
数据结构·人工智能·科技·神经网络·算法
li1670902707 小时前
第二十七章:智能指针
c语言·数据结构·c++·visual studio
代码中介商9 小时前
数据结构开篇:从问题到解决方案
数据结构
AKDreamer_HeXY10 小时前
QOJ 12255 - 36 Puzzle 题解
数据结构·c++·数学·算法·icpc·qoj
Rabitebla10 小时前
vector 的骨架:三根指针、模板陷阱与迭代器失效的第一现场
开发语言·数据结构·c++·算法