概述
list_for_each_entry在内核代码中随处可见。用于遍历链表。下面是我对它的理解。
定义
先看看宏定义:
#define list_entry(ptr, type, member)
container_of(ptr, type, member)
#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))
乍一看它是一个特定for循环头。由list_entry这个宏组成。
list_entry其实就是container_of宏,实现通过结构体成员获得结构体母体指针的方法。
在之前的文章中已经介绍过,不再赘述。
我还是习惯直接从使用中去学习它。
例子
假设有结构体如下
struct list_head {
struct list_head *next, *prev;
};
struct node
{
int val;
struct list_head my_list;
};
结构体node由my_list和val组成,my_list 是双向链表中的一环,附代码如下
#include<stdio.h>
#include<stdlib.h>
struct list_head {
struct list_head *next, *prev;
};
#define INIT_LIST_HEAD(ptr) do { (ptr)->next = (ptr); (ptr)->prev = (ptr); } while (0)
static inline void __list_add(struct list_head *add,
struct list_head *prev,
struct list_head *next)
{
next->prev = add;
add->next = next;
add->prev = prev;
prev->next = add;
}
static inline void list_add_tail(struct list_head *add, struct list_head *head)//每次添加节点都是头结点之前,由于是循环链表,就是说添加到链表尾部
{
__list_add(add, head->prev, head);
}
#define offsetof(struct_t,member) ((size_t)(char *)&((struct_t *)0)->member)
#define container_of(ptr, type, member) ({
const typeof( ((type *)0)->member ) *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type,member) );})
#define list_entry(ptr, type, member)
container_of(ptr, type, member)
#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))
struct node
{
int val;
struct list_head my_list;
};
int main()
{
struct list_head head;
struct node a,b,c,*pnode;
a.val = 1;
b.val = 2;
c.val = 3;
INIT_LIST_HEAD(&head); //初始化链表头
list_add_tail(&a.my_list,&head); //添加节点
list_add_tail(&b.my_list,&head);
list_add_tail(&c.my_list,&head);
printf("*******************************************n");
list_for_each_entry(pnode,&head,my_list)//遍历链表,打印结果
{
printf("val = %dn",pnode->val);
}//print 1 2 3
printf("*******************************************n");
struct node d,e;
d.val = 4;
e.val = 5;
list_add_tail(&d.my_list,&head);
list_add_tail(&e.my_list,&head);
list_for_each_entry(pnode,&head,my_list)
{
printf("val = %dn",pnode->val);
}//print 1 2 3 4 5
printf("*******************************************n");
return 0;
}
打印如下:
*******************************************
val = 1
val = 2
val = 3
*******************************************
val = 1
val = 2
val = 3
val = 4
val = 5
*******************************************
宏展开
好了,基于上面的例子我们来对宏进行展开
list_for_each_entry(pnode,&head,my_list)//遍历链表,打印结果
{
printf("val = %dn",pnode->val);
}
//宏展开如下
for(pnode = list_entry((&head)->next), typeof(* pnode),my_list);
&pnode->mylist != head;
pnode = list_entry((pnode->mylist).next, typeof(* pnode),my_list)
{
printf("val = %dn",pnode->val);
}
//伪代码
for(pnode=head->next的母结构体node;
当pnode->mylist的下一个链表为head时退出循环;
pnode=(pnode->mylist).next的母结构体node;)
{
printf("val = %dn",pnode->val);
}
其实 宏的第一个参数 pnode只是一个暂存器,用来遍历链表上所以的node节点。
其实 宏的第二个参数 head 是链表头的名字
其实 宏的第三个参数 my_list 是node结构体中链表成员的名字
嘿嘿,你会用了吗?
宏的实现功能就是从链表头head的下一个节点开始遍历链表的母结构体node(存于pnode中)直至链表头head的前一个节点为止。
最后
以上就是忧伤芝麻为你收集整理的linux内核常用宏 list_for_each_entry的全部内容,希望文章能够帮你解决linux内核常用宏 list_for_each_entry所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复