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为什么是废弃的?

相关推荐
gaoshou456 小时前
代码随想录训练营第三十一天|LeetCode56.合并区间、LeetCode738.单调递增的数字
数据结构·算法
闪电麦坤956 小时前
数据结构:深度优先搜索 (Depth-First Search, DFS)
数据结构·深度优先
C语言小火车11 小时前
【C++八股文】数据结构篇
数据结构·数据库·c++·c++八股文
Boop_wu12 小时前
[数据结构] 链表
数据结构·链表
闪电麦坤9512 小时前
数据结构:图的表示 (Representation of Graphs)
数据结构·算法·图论
胡萝卜3.013 小时前
【LeetCode&数据结构】设计循环队列
数据结构·算法·leetcode·队列·循环队列
闻缺陷则喜何志丹13 小时前
【线段树 懒删除堆】P12372 [蓝桥杯 2022 省 Python B] 最优清零方案|普及+
数据结构·c++·线段树·懒删除堆
闻缺陷则喜何志丹13 小时前
【 线段树】P12347 [蓝桥杯 2025 省 A 第二场] 栈与乘积|普及+
数据结构·c++·蓝桥杯·线段树·洛谷
徐归阳13 小时前
数组本身的深入解析
数据结构·c++·算法
睡不醒的kun14 小时前
leetcode算法刷题的第二十六天
数据结构·c++·算法·leetcode·职场和发展·贪心算法