关于rtthread内链表rt_list_for_each_entry的用法

电子说

1.2w人已加入

描述

各人对于链表的使用并不是很频繁,偶尔用一下,所以导致每次用都不记得怎么用了,都要重新分析一下逻辑,所以今天在这里记录一下用法,方便自己也方便用得到的小伙伴查阅。

具体的函数接口这里就不介绍了,RTThread的API文档里讲的很清楚,按照API接口调用就可以了,比较容易。

这里主要说明rt_list_for_each_entry宏的用法,因为每次就这里不太好理解,这个宏实现的功能类似C++中用引用遍历链表,很好用的。而且RTT已经给实现了这种遍历方法如果不用总感觉自己亏了点啥

先看一下代码里此宏的具体定义:

/**

rt_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 rt_list_for_each_entry(pos, head, member)
for (pos = rt_list_entry((head)->next, typeof(*pos), member);
&pos->member != (head);
pos = rt_list_entry(pos->member.next, typeof(*pos), member))

乍一看可能有点乱,所以需要稍微梳理一下逻辑,梳理通了也就不复杂了。此宏具体的实现功能肯定是要遍历链表内的每个节点成员,所以核心就是一个for循环,可每次要用这个宏的时候第一反应就是这个宏的三个参数是什么意思来着?要传入什么?那就要先分析一下for信号里面的代码了。

for循环相信大家都知道了,一般括号内有三条语句(有时把变化语句放到循环体内,这里就只有两条语句了),第一条语句可以成为初始化语句,初始化循环变量。第二条语句是循环条件语句,为真则循环为假则退出循环。第三条语句是变量变化语句。

对应到这里的宏,第一条初始化语句为pos = rt_list_entry((head)->next, typeof(*pos), member);,是一个对pos的赋值语句,所以这里结合代码和上面的注释就能很容易知道第一个参数pos就类似普通for循环的循环变量。初始化又用到了另外一个宏rt_list_entry,此宏相关的代码如下:

/**

@brief get the struct for this entry
@param node the entry point
@param type the type of structure
@param member the name of list in structure
/
#define rt_list_entry(node, type, member)
rt_container_of(node, type, member)
/
*
rt_container_of - return the member address of ptr, if the type of ptr is the
struct type.
*/
#define rt_container_of(ptr, type, member)
((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
展开后就是一个减法计算:(char *)((head)->next) - (unsigned long)(&((typeof(*pos) *)0)->member),其中&((typeof(*pos) *)0)->member的功能是得到pos类型结构体内member成员的偏移地址。把0地址看做一个pos类型的结构体,再取其中任何成员的地址就自然是其偏移地址了。
所以这个宏的pos参数,传入的应该是你自己定义的链表节点结构体指针,此结构体内包含一个rt_list_t类型的member成员变量。所以第三个参数传入一个rt_list_t member变量即可。而第二个参数head传入的是链表头节点内的member变量指针。所以这里for循环内的第一条初始化语句就是初始化pos为链表内第一个节点的自定义结构体指针。

理解到这里,第二条语句就很容易理解了,就是判断遍历的pos内的下一个节点指针是不是又回到了head(单向链表里是判断是否为NULL),是则已经遍历一遍,退出循环。

第三条语句是取pos->member.next也就是下一个节点对于的自己定义结构体指针。

为了方便理解上面的内容,下面给出一个简单的例子:

typedef struct __test_node
{
rt_uint16_t a; //可加入任何类型的用户自定义变量
rt_uint16_t b;
rt_uint16_t c;
rt_list_t member;
}TestNode;
void rt_list_test()
{
TestNode test_head;
rt_list_init(&test_head.member);
for(int i = 0; i < 10; ++i) {
TestNode *new_node = rt_malloc(sizeof(TestNode));
new_node->a = i;
rt_list_insert_before(&test_head.member, &new_node->member);
}
rt_kprintf("list_len:%dn",rt_list_len(&test_head.member));
TestNode *list_pos;
rt_list_t member;
rt_list_for_each_entry(list_pos, &test_head.member, member)
{
rt_kprintf("a:%dn", list_pos->a);
}
}

运行结果:

for循环

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分