经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C 语言 » 查看文章
C 语言通用模板队列(宏函数)
来源:cnblogs  作者:大橙子疯  时间:2021/6/7 9:14:59  对本文有异议

前言

       嵌入式开发过程中,各个模块之间,各个设备之间进行交互时,都会存在数据的输入输出,由于处理的方式不同,数据不会立即同步处理,因此通常在设计时都会设计缓冲区进行数据的处理,方式数据丢失等问题;

       一个项目中存在不同模块都需要缓冲区的设计,设计策略基本都一样,不同的是数据结构,在 C 语言中可以编写缓冲区功能函数,入参类型通常为无类型指针,适配所有需要储存的不同数据结构,但是这种方式必须先知道不同数据结构体的大小,在写入和读取时按一个个字节操作。

       下面介绍的是使用宏定义函数实现该方式,按照数据结构的形式赋值速度快,效率高,但是需要一定内存(宏定义替换),以空间换时间。


背景

之前我写的数据队列功能函数,有两种实现方式。

固定类型指针入参

队列的入参类型为固定类型指针,如: QueuePushData(TestInfo_t *pQueueBuf, TestInfo_t *pSrcData, QueueCtrl *pCtrl)。

优点是数据写入/读取效率高(类型的大小内存拷贝),缺点是函数功能不能复用

无类型指针入参

队列的入参类型为无类型指针,如: QueuePushData(void *pQueueBuf, void *pSrcData, QueueCtrl *pCtrl)。

优点是函数功能可复用(无类型编译不报错),缺点是数据写入/读取效率和固定类型比较低(通过单字节或 memcpy() 等方式拷贝),且队列控制中需要增加队列数据的占用大小


实现方式

为了达到数据写入/读取效率高函数功能可复用两种优点,通过宏定义函数的方式实现(相对函数来说,占用代码空间,内存足够的情况下目的是以空间换时间)。

宏定义函数实现数据队列的功能,适用不同数据结构,类似于 C++ 的模板方式,相同的实现逻辑,不同的数据结构。

结构体定义

首先对需要定义一个数据队列的控制句柄和一些控制状态掩码

点击查看代码
  1. /**
  2. * @brief 缓存区操作信息结构体定义
  3. */
  4. typedef struct{
  5. uint8_t state; /*!< 控制状态 */
  6. uint8_t end; /*!< 循环队列尾哨兵 */
  7. uint8_t head; /*!< 循环队列首哨兵 */
  8. uint8_t num; /*!< 循环队列中能存储的最多组数 */
  9. } QueueCtrl_t;
  10. #define QUEUE_ENABLE_COVER (0X80)
  11. #define QUEUE_EXIT_DATA (0X01)
  12. #define QUEUE_DATA_FULL (0X02)
  13. #define QUEUE_DATA_LOCK (0X04)

队列的初始化

定义数据队列的控制句柄,需要初始化这个句柄,之后才能正常操作队列。

点击查看代码
  1. /**
  2. * @brief 队列控制初始化
  3. *
  4. * @param[in,out] ctrl - 队列控制句柄
  5. * @param[in] num - 队列数目大小
  6. * @param[in] cover - 0,不覆盖; 1,队列满了覆盖顶端数据
  7. */
  8. #define QUEUE_INIT(ctrl, maxNum, cover) ({ ctrl.end = 0; ctrl.head = 0; ctrl.num = (maxNum); ctrl.state = 0x00; ctrl.state |= ((cover) ? QUEUE_ENABLE_COVER : 0);})

队列的存放

初始化完后,则可以写入数据至队列当中

点击查看代码
  1. /**
  2. * @brief 在队列末尾加入新的数据
  3. *
  4. * @param[in,out] dstLists - 队列缓存区
  5. * @param[in] src - 新的数据
  6. * @param[in,out] ctrl - 队列控制句柄
  7. * @retval 返回的值含义如下
  8. * @arg 0: 写入成功
  9. * @arg -1: 写入失败
  10. */
  11. #define QUEUE_PUSH_DATA(dstLists, src, ctrl) ({ int ret = 0; if (QUEUE_DATA_LOCK != ((ctrl.state) & QUEUE_DATA_LOCK)) { dstLists[(ctrl.end)++] = src; (ctrl.state) |= QUEUE_EXIT_DATA; if ((ctrl.end) >= (ctrl.num)) { (ctrl.end) = 0; } if (((ctrl.state) & QUEUE_DATA_FULL) == QUEUE_DATA_FULL) { (ctrl.head) = (ctrl.end); } else if ((ctrl.end) == (ctrl.head)) { (ctrl.state) |= QUEUE_DATA_FULL; if ((ctrl.state & QUEUE_ENABLE_COVER) != QUEUE_ENABLE_COVER) { (ctrl.state) |= QUEUE_DATA_LOCK; } } ret = 0; } else { ret = -1; } ret;})

队列的读取

点击查看代码
  1. /**
  2. * @brief 在队列顶端读取数据
  3. *
  4. * @param[in,out] dstLists - 队列缓存区
  5. * @param[out] dst - 读取的数据
  6. * @param[in,out] ctrl - 队列控制句柄
  7. * @retval 返回的值含义如下
  8. * @arg 0: 读取成功
  9. * @arg -1: 读取失败
  10. */
  11. #define QUEUE_POP_DATA(dstLists, dst, ctrl) ({ int ret = -1; if (((ctrl.state) & QUEUE_EXIT_DATA) == QUEUE_EXIT_DATA) { dst = dstLists[ctrl.head++]; if ((ctrl.head) >= (ctrl.num)) { ctrl.head = 0; } if ((ctrl.head) == (ctrl.end)) { if (((ctrl.state) & QUEUE_DATA_FULL) != QUEUE_DATA_FULL) { (ctrl.state) &= ~QUEUE_EXIT_DATA; } } ret = 0; } (ctrl.state) &= ~QUEUE_DATA_LOCK; (ctrl.state) &= ~QUEUE_DATA_FULL; ret;})

Demo测试代码

正在加载Demo编译器插件,可能较慢,稍等

原文链接:http://www.cnblogs.com/const-zpc/p/14848720.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号