zephyr学习笔记---单向链表slist
来源:互联网 发布:网络连接突然出现叹号 编辑:程序博客网 时间:2024/06/05 18:11
看了下zephyr所支持的开发板,有一个TI公司的,CC3200。低功耗wifi芯片,淘宝了一下,200出头,可以接受。当即买了一块,先弄TCP/IP再学6LowPan会好些。现在等开发板到货。
在链表list中删除节点node。
上面两个遍历一般用不到,只是为下两个遍历提供服务
引用:
http://blog.csdn.net/abatei/article/details/66970546
开发环境已经装好,ubuntu下开发,请参考大牛写的:
http://iot-fans.xyz/zephyr/doc/v1.6.0/getting_started/installation_linux.html
最好对照原文:
https://www.zephyrproject.org/doc/getting_started/installation_linux.html
开发板没到,先搞些基础工作,从简单的入手吧。先分析几个基础数据结构。首先就是单向链表slist。
slist.h文件存在于zephyr / include / misc文件夹下,全部使用内联函数,无相应的.c文件。slist为单向非循环链表,具备头指针和尾指针,下面说说它的常用函数:
static inline void sys_slist_init(sys_slist_t *list)
初始化链表,其实就是将头指针和尾指针置空。
static inline bool sys_slist_is_empty(sys_slist_t *list)
判断list是否为空链表,返回true为空,false为非空。
static inline sys_snode_t *sys_slist_peek_head(sys_slist_t *list)
返回list的头节点。
static inline sys_snode_t *sys_slist_peek_tail(sys_slist_t *list)
返回list的尾节点
static inline sys_snode_t *sys_slist_peek_next_no_check(sys_snode_t *node)
返回node的下一个节点,注意,必须已确定node不为空。此函数是不检查node是否为空的,所以速度会快些
static inline sys_snode_t *sys_slist_peek_next(sys_snode_t *node)
和上一个函数功能相同,在无法确定node是否为空的情况下使用。如果node为空,则返回NULL。
static inline void sys_slist_append(sys_slist_t *list,
sys_snode_t *node)
sys_snode_t *node)
将节点node追加至list链表的尾部
static inline void sys_slist_prepend(sys_slist_t *list,
sys_snode_t *node)
sys_snode_t *node)
将节点node添加至list链表的头部,成为头节点。链表有这样的功能估计是为将来成为栈或队列作准备的。
static inline void sys_slist_append_list(sys_slist_t *list,
void *head, void *tail)
{
if (!list->tail)
{
list->head = (sys_snode_t *)head;
list->tail = (sys_snode_t *)tail;
}
else
{
list->tail->next = (sys_snode_t *)head;
list->tail = (sys_snode_t *)tail;
}
}
void *head, void *tail)
{
if (!list->tail)
{
list->head = (sys_snode_t *)head;
list->tail = (sys_snode_t *)tail;
}
else
{
list->tail->next = (sys_snode_t *)head;
list->tail = (sys_snode_t *)tail;
}
}
参数list:源链表
参数head:要追加链表的头节点
参数tail:要追加链表的尾节点
函数功能:将头节点为head、尾节点为tail的链表追加到源链表list后面。
static inline void sys_slist_merge_slist(sys_slist_t *list,
sys_slist_t *list_to_append)
{
sys_slist_append_list(list, list_to_append->head,
list_to_append->tail);
sys_slist_init(list);
}
sys_slist_t *list_to_append)
{
sys_slist_append_list(list, list_to_append->head,
list_to_append->tail);
sys_slist_init(list);
}
将链表list和链表list_to_append合并,list_to_append追加至list尾部。添加完后,list被清空。
这里有些看不懂,故将源码放上。list被清空,新链表就找不到了,因为list_to_append指向的还是追加前的链表,追加后的链表再也找不到。除非原本另有指针指向list的头尾节点。个人感觉,被清空的应该是list_to_append。
static inline void sys_slist_insert(sys_slist_t *list,
sys_snode_t *prev,
sys_snode_t *node)
sys_snode_t *prev,
sys_snode_t *node)
在链表list的prev节点后插入新节点node。
static inline sys_snode_t *sys_slist_get_not_empty(sys_slist_t *list)
删除链表的头节点,必须确定list不为空链表才能使用此函数。
static inline sys_snode_t *sys_slist_get(sys_slist_t *list)
跟上个函数一样,删除链表头节点,list可以为空链表。
static inline void sys_slist_remove(sys_slist_t *list,
sys_snode_t *prev_node,
sys_snode_t *node)
sys_snode_t *prev_node,
sys_snode_t *node)
在链表list中删除节点node。必须给出node的上一个节点prev_node作为参数。如果不想给出上一个节点,请使用下面这个函数。
static inline void sys_slist_find_and_remove(sys_slist_t *list,
sys_snode_t *node)
sys_snode_t *node)
下面是几个遍历用的宏:
#ifndef __SLIST_H__
#define __SLIST_H__
/**
* @brief 遍历整张链表
* Note: 循环不安全,因此__sn不能被,简而言之就是不能用于删除操作。
*
* 用户必须自行添加大括号以指定循环体
*
* SYS_SLIST_FOR_EACH_NODE(l, n) {
* <user code>
* }
*
* @param __sl 指向sys_slist_t类型的指针,表示将进行迭代的链表
* @param __sn sys_snode_t类型指针,用于遍历链表中的每个节点
*/
#define SYS_SLIST_FOR_EACH_NODE(__sl, __sn) \
for (__sn = sys_slist_peek_head(__sl); __sn; \
__sn = sys_slist_peek_next(__sn))
/**
* @brief 从链表指定节点处遍历到结尾
* Note: 循环不安全,因此__sn不能被删除,简而言之就是不能用于删除操作。
*
* 用户自行加大括号
*
* SYS_SLIST_ITERATE_FROM_NODE(l, n) {
* <user code>
* }
*
* 和SYS_SLIST_FOR_EACH_NODE()一样, 但如__sn指定为链表中的一个节点,
* 则遍历从__sn的下一个节点开始。如果__sn为空,则从头节点开始遍历。
*
* @param __sl 指向sys_slist_t类型的指针,表示将进行迭代的链
* @param __sn sys_snode_t类型指针,指定的开始节点,为空则从头开始
*/
#define SYS_SLIST_ITERATE_FROM_NODE(__sl, __sn) \
for (__sn = __sn ? sys_slist_peek_next_no_check(__sn) \
: sys_slist_peek_head(__sl); \
__sn; \
__sn = sys_slist_peek_next(__sn))
/**
* @brief 安全地遍历整个链表
* Note: __sn可被删除, 它不会打断循环.
*
* 用户必须自行添加大括号:
*
* SYS_SLIST_FOR_EACH_NODE_SAFE(l, n, s) {
* <user code>
* }
*
* @param __sl sys_slist_t类型指针,指向被遍历链表
* @param __sn sys_snode_t类型指针,依次等于链表中的每个节点
* @param __sns sys_snode_t类型指针,用于安全遍历
*/
#define SYS_SLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \
for (__sn = sys_slist_peek_head(__sl), \
__sns = sys_slist_peek_next(__sn); \
__sn; __sn = __sns, \
__sns = sys_slist_peek_next(__sn))
#define __SLIST_H__
/**
* @brief 遍历整张链表
* Note: 循环不安全,因此__sn不能被,简而言之就是不能用于删除操作。
*
* 用户必须自行添加大括号以指定循环体
*
* SYS_SLIST_FOR_EACH_NODE(l, n) {
* <user code>
* }
*
* @param __sl 指向sys_slist_t类型的指针,表示将进行迭代的链表
* @param __sn sys_snode_t类型指针,用于遍历链表中的每个节点
*/
#define SYS_SLIST_FOR_EACH_NODE(__sl, __sn) \
for (__sn = sys_slist_peek_head(__sl); __sn; \
__sn = sys_slist_peek_next(__sn))
/**
* @brief 从链表指定节点处遍历到结尾
* Note: 循环不安全,因此__sn不能被删除,简而言之就是不能用于删除操作。
*
* 用户自行加大括号
*
* SYS_SLIST_ITERATE_FROM_NODE(l, n) {
* <user code>
* }
*
* 和SYS_SLIST_FOR_EACH_NODE()一样, 但如__sn指定为链表中的一个节点,
* 则遍历从__sn的下一个节点开始。如果__sn为空,则从头节点开始遍历。
*
* @param __sl 指向sys_slist_t类型的指针,表示将进行迭代的链
* @param __sn sys_snode_t类型指针,指定的开始节点,为空则从头开始
*/
#define SYS_SLIST_ITERATE_FROM_NODE(__sl, __sn) \
for (__sn = __sn ? sys_slist_peek_next_no_check(__sn) \
: sys_slist_peek_head(__sl); \
__sn; \
__sn = sys_slist_peek_next(__sn))
/**
* @brief 安全地遍历整个链表
* Note: __sn可被删除, 它不会打断循环.
*
* 用户必须自行添加大括号:
*
* SYS_SLIST_FOR_EACH_NODE_SAFE(l, n, s) {
* <user code>
* }
*
* @param __sl sys_slist_t类型指针,指向被遍历链表
* @param __sn sys_snode_t类型指针,依次等于链表中的每个节点
* @param __sns sys_snode_t类型指针,用于安全遍历
*/
#define SYS_SLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \
for (__sn = sys_slist_peek_head(__sl), \
__sns = sys_slist_peek_next(__sn); \
__sn; __sn = __sns, \
__sns = sys_slist_peek_next(__sn))
/**
* @brief 提供根据容器建立的链表的遍历原语
* Note: 此循环不安全,因此不能被删除
*
* 用户必须自行加大括号:
*
* SYS_SLIST_FOR_EACH_CONTAINER(l, c, n) {
* <user code>
* }
*
* @param __sl sys_slist_t指针,将遍历此链表
* @param __cn 用于遍历链表元素的临时指针变量,为容器类型
* @param __n sys_node_t在容器结构体中的类型名称
*/
#define SYS_SLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \
for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n); __cn; \
__cn = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n))
* @brief 提供根据容器建立的链表的遍历原语
* Note: 此循环不安全,因此不能被删除
*
* 用户必须自行加大括号:
*
* SYS_SLIST_FOR_EACH_CONTAINER(l, c, n) {
* <user code>
* }
*
* @param __sl sys_slist_t指针,将遍历此链表
* @param __cn 用于遍历链表元素的临时指针变量,为容器类型
* @param __n sys_node_t在容器结构体中的类型名称
*/
#define SYS_SLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \
for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n); __cn; \
__cn = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n))
下面这个是安全遍历
/**
* @brief 提供根据容器建立的链表的安全遍历原语
* Note: __cn 可以被删除,不会打断循环.
*
* User 用户必须自行添加大括号:
*
* SYS_SLIST_FOR_EACH_NODE_SAFE(l, c, cn, n) {
* <user code>
* }
*
* @param __sl sys_slist_t类型指针,将遍历此链表
* @param __cn 用于遍历链表元素的临时指针变量,为容器类型
* @param __cns 用于安全遍历的临时变量,和__cn同类型
* @param __n sys_node_t在容器结构体中的类型名称
*/
#define SYS_SLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n) \
for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n), \
__cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n); __cn; \
__cn = __cns, __cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n))
* @brief 提供根据容器建立的链表的安全遍历原语
* Note: __cn 可以被删除,不会打断循环.
*
* User 用户必须自行添加大括号:
*
* SYS_SLIST_FOR_EACH_NODE_SAFE(l, c, cn, n) {
* <user code>
* }
*
* @param __sl sys_slist_t类型指针,将遍历此链表
* @param __cn 用于遍历链表元素的临时指针变量,为容器类型
* @param __cns 用于安全遍历的临时变量,和__cn同类型
* @param __n sys_node_t在容器结构体中的类型名称
*/
#define SYS_SLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n) \
for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n), \
__cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n); __cn; \
__cn = __cns, __cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n))
读完代码写程序,这时才发现使用CCS进行TI-RTOS是一件多么幸福的事情,用VS开发C#那简直是在天堂了。开发环境没搭太好,qemu又不懂如何关闭,总之各种折磨。总算写完,看来得花时间找找有什么办法心善下开发环境。
先上代码:
先记下环境变量设置命令,方便以后回来对照:export ZEPHYR_GCC_VARIANT=zephyr
export ZEPHYR_SDK_INSTALL_DIR=~/zephyr-sdk
cd zephyr-project/
source zephyr-env.sh
export ZEPHYR_SDK_INSTALL_DIR=~/zephyr-sdk
cd zephyr-project/
source zephyr-env.sh
由于关闭不了qemu,每编译一次都要打一轮。之后再解决这个问题
(经tidyjiang大神指点,已解决qemu关闭问题:先按Ctrl+a,再按x退出。不要忘记他的博客,上篇日志提到过:http://blog.csdn.net/tidyjiang/article/details/51622186)
然后通过以下命令在qemu上执行程序:
make BOARD=qemu_x86 qemu
所有命令及运行结果如下图所示:
本例演示了slist的添加、删除、插入及遍历操作。要使用链表,必须在链表所存储元素所使用结构体中添加一个sys_snode_t类型成员,这个结构体被为容器(container)。这样使用比较麻烦,在这点上contiki中的链表比zephyr更先进、好用些。另外我始终认为链表如果进出操作太多,会产生大量零碎空间,应当慎用。C#中基本没见哪个地方使用链表,有使用的地方基本都用静态链表代替。
http://blog.csdn.net/abatei/article/details/66970546
0 0
- zephyr学习笔记---单向链表slist
- C++ STL学习笔记五 slist单向链表容器
- C++ STL学习笔记五 slist单向链表容器
- C++ STL学习笔记五 slist单向链表容器
- 单向链表-slist
- zephyr学习笔记---双向链表dlist
- STL源码剖析——单向链表slist
- STL(九)slist单向链表容器
- zephyr学习笔记---前言
- 单向链表学习笔记
- 学习笔记--单向链表
- zephyr学习笔记---CC3200---GPIO
- zephyr学习笔记---CC3200---Button
- zephyr学习笔记---CC3200---GPIO
- zephyr学习笔记---CC3200---Button
- STL学习笔记之容器--slist
- C++学习笔记之单向链表
- slist双向链表容器
- linux共享内存的两种方式
- HDU1358 Period(KMP找循环前缀)
- Android ContentProvider 完全解析及DEMO(最具说服力)
- OpenGL ES简介
- Oracle中merge into的使用
- zephyr学习笔记---单向链表slist
- 说说 -webkit-tap-highlight-color 属性
- poj1061——青蛙的约会(扩展欧几里得)
- 从归并排序到逆序对数目计算。
- AppDelegate中几个常用的回调调用时机
- java转php 关于向上转型和多态解惑
- Git Stash用法
- 从上往下打印二叉树
- Android Studio 编译占 cpu99%、100%、编译超慢、卡断问题分析