前言

嵌入式开发过程中,各个模块之间,各个设备之间进行交互时,都会存在数据的输入输出,由于处理的方式不同,数据不会立即同步处理,因此通常在设计时都会设计缓冲区进行数据的处理,方式数据丢失等问题;一个项目中存在不同模块都需要缓冲区的设计,设计策略基本都一样,不同的是数据结构,在 C 语言中可以编写缓冲区功能函数,入参类型通常为无类型指针,适配所有需要储存的不同数据结构,但是这种方式必须先知道不同数据结构体的大小,在写入和读取时按一个个字节操作。

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

实现方式

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

点击查看代码

/**
* @brief 缓存区操作信息结构体定义
*/
typedef struct{
uint8_t state; /*!< 控制状态 */ uint8_t end; /*!< 循环队列尾哨兵 */ uint8_t head; /*!< 循环队列首哨兵 */ uint8_t num; /*!< 循环队列中能存储的最多组数 */
} QueueCtrl_t; #define QUEUE_ENABLE_COVER (0X80)
#define QUEUE_EXIT_DATA (0X01)
#define QUEUE_DATA_FULL (0X02)
#define QUEUE_DATA_LOCK (0X04) /**
* @brief 队列控制初始化
*
* @param[in,out] ctrl - 队列控制句柄
* @param[in] num - 队列数目大小
* @param[in] cover - 0,不覆盖; 1,队列满了覆盖顶端数据
*/
#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);\
}) /**
* @brief 在队列末尾加入新的数据
*
* @param[in,out] dstLists - 队列缓存区
* @param[in] src - 新的数据
* @param[in,out] ctrl - 队列控制句柄
* @retval 返回的值含义如下
* @arg 0: 写入成功
* @arg -1: 写入失败
*/
#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;\
}) /**
* @brief 在队列顶端读取数据
*
* @param[in,out] dstLists - 队列缓存区
* @param[out] dst - 读取的数据
* @param[in,out] ctrl - 队列控制句柄
* @retval 返回的值含义如下
* @arg 0: 读取成功
* @arg -1: 读取失败
*/
#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测试代码

C 语言通用模板队列的更多相关文章

  1. PHP中的位运算与位移运算(其它语言通用)

    /* PHP中的位运算与位移运算 ======================= 二进制Binary:0,1 逢二进1,易于电子信号的传输 原码.反码.补码 二进制最高位是符号位:0为正数,1为负数( ...

  2. go语言的模板,text/template包

    go语言的模板,text/template包 定义 模板就是将一组文本嵌入另一组文本里 传入string--最简单的替换 package main import ( "os" &q ...

  3. C语言实现,队列可伸缩

    两个栈实现一个队列,C语言实现,队列可伸缩,容纳任意数目的元素. 一.思路:1.创建两个空栈A和B:2.A栈作为队列的入口,B栈作为队列的出口:3.入队列操作:即是入栈A:4.出队列操作:若栈B为空, ...

  4. Django模板之通用模板的使用

    Django模板之通用模板的使用 转载:https://code.ziqiangxuetang.com/django/django-template.html 我们做网站有一些通用的部分,比如 导航, ...

  5. 「小程序JAVA实战」小程序通用模板的使用(17)

    转自:https://idig8.com/2018/08/09/xiaochengxu-chuji-17/ 小程序也为了页面增加了通用模板的功能,如何去理解一个通用的模板呢?模板的定义就是为了让我们的 ...

  6. Xamarin XAML语言教程模板视图TemplatedView(二)

    Xamarin XAML语言教程模板视图TemplatedView(二) (2)打开MainPage.xaml文件,编写代码,将构建的控件模板应用于中TemplatedView.代码如下: <? ...

  7. Xamarin XAML语言教程模板视图TemplatedView(一)

    Xamarin XAML语言教程模板视图TemplatedView(一) 模板视图TemplatedView 与模板页面相对的是TemplatedView,它被称为模板视图,它的功能和模板页面类似,也 ...

  8. Xamarin XAML语言教程模板页面TemplatedPage

    Xamarin XAML语言教程模板页面TemplatedPage 模板页面TemplatedPage 在上文中我们提到了TemplatedPage,它被称为模板页面,用来显示控件模版.Templat ...

  9. Loadrunner:脚本编写通用模板(Http协议类型)

    1. 背景 对于 Http协议,Loadrunner 脚本可以使用通用模板反复粘贴,只需要修改其中的 URL 和 传参,就可以完成一整个业务 2. Get 类型的接口 web_custom_reque ...

随机推荐

  1. java面试一日一题:java的类加载过程

    问题:请讲下java的类加载机制及过程 分析:该问题主要考察对JVM加载类的机制及过程,延申出的问题是为什么使用双亲委托模型,有什么办法可以打破双亲委托吗: 回答要点: 主要从以下几点去考虑, 1.类 ...

  2. python 函数基本内容

    1.什么是函数? 函数就是盛放代码的容器,把实现某一功能的一组代码丢到一个函数中就做成了一个小工具具备某一功能的工具->函数事先准备工具的过程->函数的定义遇到应用场景拿来就用->函 ...

  3. 浅谈跨域问题,CORS跨域资源共享

    1,何为跨域? 在理解跨域问题之前,你先要了解同源策略和URL,简单叙述: 1)同源策略 三同:协议相同,域名相同,端口相同: 目的:保证用户信息安全,防止恶意网站窃取数据.同源策略是必须的,否则co ...

  4. Selenium3自动化测试【14】元素定位之ID

    元素定位 Selenium需要告知其如何去定位元素,来模拟用户动作.例如要操作Bing搜索页. 首先要找到搜索框与搜索按钮: 通过键盘输入检索的关键字: 用鼠标单击搜索按钮: 提交搜索请求. Sele ...

  5. 【CompletableFuture】CompletableFuture测试runAsync()方法调用

    问题 CompletableFuture.runAsync() 返回 CompletableFuture<Void>对象,调用CompletableFuture.allOf(f1,f2). ...

  6. Python中math和cmath模块的使用

    目录 Math模块 Cmath模块 Math模块 pi                数字常量,圆周率 e                 表示一个常量 sqrt(x)         求x的平方根 ...

  7. POJ1376简单广搜

    题意:       给你一个n*m的矩阵,然后给你机器人的起点和终点,还有起点的方向,然后每次机器人有两种操作,左右旋转90度,或者是朝着原来的方向走1,2或者3步,机器人再走的过程中不能碰到格子,也 ...

  8. 逆向 stdio.h 函数库 fopen 函数(调试版本)

    0x01 fopen 函数 函数原型:FILE *fopen(const char *filename, const char *mode) 返回值为 FILE 类型 函数功能:使用给定的模式 mod ...

  9. postman使用教程7-参数化引用外部文件测试数据

    前言 当同一个接口需要测试不同的参数时,需用到参数化的概念.postman支持从外部文件读取测试数据参数化 设置参数化变量 新建一个collections 专门测试登录接口 设置集合变量usernam ...

  10. .NET之API版本控制

    1. 优点 有助于保护原有系统,不受影响,并及时修改问题 可以实现用户的私人定制(比如是付费接口) 快速迭代 2. API版本控制 在URL中追加版本或者作为查询字符串参数 通过自动以标头和通过接受标 ...