0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

关于rtthread内链表rt_list_for_each_entry的用法

冬至子 来源:吉利咕噜2022 作者:吉利咕噜2022 2023-08-07 15:17 次阅读

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

具体的函数接口这里就不介绍了,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);
}
}

运行结果:

1.jpg

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

    关注

    1

    文章

    26

    浏览量

    16839
  • C++语言
    +关注

    关注

    0

    文章

    147

    浏览量

    6990
  • RTThread
    +关注

    关注

    8

    文章

    132

    浏览量

    40861
  • for循环
    +关注

    关注

    0

    文章

    61

    浏览量

    2502
收藏 人收藏

    评论

    相关推荐

    【Linux高级编译】list.h的高效应用—双向链表的实现

    【Linux高级编译】Linux内核的list.h的高效应用——双向链表的实现
    的头像 发表于 09-15 10:00 2601次阅读
    【Linux高级编译】<b class='flag-5'>list</b>.h的高效应用—双向<b class='flag-5'>链表</b>的实现

    rtthread 5.20安装systemview 2.52a出错的原因?

    rt_thread\' thread = rt_list_entry(node, struct rt_thread, list); 提示 packages/SystemView
    发表于 07-12 09:36

    Linux内核的链表操作

    = list_entry(i, struct nf_sockopt_ops, list); 大多数情况下,遍历链表的时候都需要获得链表节点数据项,也就是说
    发表于 08-29 11:13

    Linux Kernel数据结构:链表

    连接起来,形成链表,通过通用的链表函数来进行操作。有点可想而知,这个通用的链表操作函数可以搞定所有的链表,实现了代码的重用。如果想得到对应结构的指针,可以使用
    发表于 09-25 16:41

    RT-Thread内核中单链表的使用与实现

    rt_slist_for_each_entry(node(节点), struct (结构体), list(链表所在结构体成员中的名字))3. 单链表的实现初始化
    发表于 04-01 12:01

    RT-Thread内核中双链表的使用与实现

    , head)遍历链表中的结构体成员···rt_list_for_each_entry(node(节点), struct (结构体), list(链表所在结构体成员中的名字))···安
    发表于 04-01 12:05

    RT-Thread中普通链表和侵入式链表有何区别

    普通链表学习数据结构的时候写的链表是下面这个样子侵入式链表RT-Thread 以及 Linux 内核中链表是这样定义的在使用的时候是这样
    发表于 04-11 15:15

    rt_timer_check造成任务不执行问题如何处理呢?

    rtthread1和rtthread2的sleep时间同时到达后,会在rt_timer_check,将超时任务由timer移除,放置到ready_
    发表于 05-10 09:47

    浅析RT-Thread中对象容器与双链表的操作

    = rt_hw_interrupt_disable();/* 把对象信息插入到对象链表中 */rt_list_insert_after(&(information->object_list
    发表于 05-18 14:23

    小编科普一下rtthread链表操作的几个API与实用的几个宏

    rtthread 链表操作的的几个 API /* 将节点 n 插入到节点 l 的后面,如果 l 为头节点,则插入到链表头部 */rt_inline void
    发表于 05-18 14:26

    rt_timer_check 造成任务不执行问题如何解决

    rt_timer_check,将超时任务由timer移除,放置到ready_list中。 由于rtthread1比rtthread2的优先
    发表于 08-09 10:25

    请问一下链表这么使用有问题吗

    ;send_data_cache_head.list)){rt_list_for_each_entry_safe(pos, n, &send_data_cache_head.list,
    发表于 08-29 11:30

    如何去解决单链表rt_slist_for_each宏问题呢

    #define rt_slist_for_each(pos, head)for (pos = (head)->next; pos != RT_NULL; pos = pos-&
    发表于 11-10 11:50

    RT-Thread中侵入式链表的应用有哪些呢

    上一个结点 /};typedef struct rt_list_node rt_list_t;/ 链表类型 */在使用的时候是这样定义的struct rt_object
    发表于 12-05 13:59

    FreeRTOS代码剖析之5:链表管理list.c

    链表是操作系统中常用的数据结构,其结构比较简单,因此在剖析FreeRTOS的内核时先从这里开始入手。 链表是由众多链表节点组成的,在FreeRTOS中,链表节点有两种定义,分别是xLI
    发表于 02-09 02:57 706次阅读
    FreeRTOS代码剖析之5:<b class='flag-5'>链表</b>管理<b class='flag-5'>list</b>.c