C语言循环数组做FIFO队列
在做通信时,FIFO队列queue是非常好用的,先完成接收通信把接收的数据存在队列里;然后再进行先进先出逐项处理。
C语言用循环数组,通过读位置和写位置循环来实现FIFO队列功能。即数组队列。
1 以1个字节为单位的数组队列的数据结构
使用数组队列,为了方便判断队列空和队列满,使用不完全填满队列,即保留一个元素始终不用
下面是两个例子
- char usart1_rev_buf[USART1_BUFFER_MAX_SIZE] = {0}; //usart receive buffer.
- unsigned short usart1_r = 0; //usart receive buffer read position.
- unsigned short usart1_w = 0; //usart receive buffer write position.
- char sendBufForUsart[SEND_BUF_MAX_SIZE] = {0}; //usart send buffer.
- unsigned short sendWrite = 0; //usart send buffer write position.
- unsigned short sendRead = 0; //usart send buffer read position.
记住:
sendRead 是下一个将要读取的位置,现在还未读取。
相当于队列头front,可执行delete操作。
sendWrite 是下一个将要写入的位置,现在还未写入。
相当于队列尾rear,可执行insert操作。
保留不用的元素位置是((
sendRead+SEND_BUF_MAX_SIZE-1)%SEND_BUF_MAX_SIZE)。
判断队列空?
sendRead == sendWrite
判断队列满? (sendWrite+1)%SEND_BUF_MAX_SIZE == sendRead
写操作
WrData为待写入的字节内容,WrBuf为待写入的内容buf,WrLen为待写的长度。
写一个字节
- if ((usart1_w+1)%USART1_BUFFER_MAX_SIZE != usart1_r)
- {
- usart1_rev_buf[usart1_w] = WrData;
- usart1_w = (usart1_w+1) % USART1_BUFFER_MAX_SIZE;
- }
写多个字节
- unsigned short emptyLen;
- unsigned short tmpAddr;
- unsigned short tmpLen;
- emptyLen = (sendRead+SEND_BUF_MAX_SIZE-(sendWrite+1)) % SEND_BUF_MAX_SIZE;
- if (emptyLen >= WrLen)
- {
- tmpAddr = (sendWrite+WrLen) % SEND_BUF_MAX_SIZE;
- if (tmpAddr <= sendWrite) //If Circular array have inverse to begin.
- {
- tmpLen =WrLen - tmpAddr;
- memcpy(&sendBufForUsart[sendWrite], WrBuf, tmpLen); //bug place
- memcpy(&sendBufForUsart[0], WrBuf+tmpLen, tmpAddr);
- }
- else
- {
- memcpy(&sendBufForUsart[sendWrite], WrBuf, WrLen);
- }
- sendWrite = tmpAddr;
- }
读操作
RdBuf为存储读取内容的buf,RdLen为待读的长度。
读一个字节
- if (usart1_r != usart1_w) //Have new data in usart receive buffer.
- {
- *RdBuf = usart1_rev_buf[usart1_r];
- usart1_r = (usart1_r+1) % USART1_BUFFER_MAX_SIZE; //Read out one byte.
- }
读多个字节
- unsigned short validLen;
- unsigned short tmpAddr;
- unsigned short tmpLen;
- validLen = (sendWrite+SEND_BUF_MAX_SIZE-sendRead) % SEND_BUF_MAX_SIZE;
- if (validLen >= RdLen)
- {
- tmpAddr = (sendRead+RdLen) % SEND_BUF_MAX_SIZE;
- if (tmpAddr <= sendRead) //If Circular array have inverse to begin.
- {
- tmpLen =RdLen - tmpAddr;
- memcpy(RdBuf, &sendBufForUsart[sendRead], tmpLen);
- memcpy(RdBuf+tmpLen, &sendBufForUsart[0], tmpAddr);
- }
- else
- {
- memcpy(RdBuf, &sendBufForUsart[sendRead], RdLen);
- }
- sendRead = tmpAddr;
- }
10.2 以固定N_LEN个字节为单位的队列的数据结构。使用二维数组队列。
要求每次写队列和每次读队列,长度都固定是
N_LEN。
下面是一个例子,每次读写固定长度为
CMD_LENGTH,
我使用二维数组实现。根据应用不同,也可选结构体数组。
- char sendBufForUsart[SEND_BUF_MAX_NUM][CMD_LENGTH] = {0};
- unsigned short sendWrite = 0;
- unsigned short sendRead = 0;
写CMD_LENGTH长度
- if ((sendWrite+1)%SEND_BUF_MAX_NUM != sendRead) //Have new data.
- {
- memcpy(&sendBufForUsart[sendWrite][0], WrBuf, CMD_LENGTH);
- sendWrite = (sendWrite+1) % SEND_BUF_MAX_NUM; //Read out one byte.
- }
读CMD_LENGTH长度
- if (sendRead != sendWrite)
- {
- memcpy(RdBuf, &sendBufForUsart[sendRead][0], CMD_LENGTH);
- sendRead = (sendRead + 1) % SEND_BUF_MAX_NUM;
- }
用结构可以更明了的说明循环队列的使用
- *typedef struct{
- * valuetype data[MAXSIZE]; [>数据的存储区<]
- * int font, rear; [>队首队尾<]
- * int num; [>队列中元素的个数<]
- *}Circular_Queue;
以上是根据本人经验的一些认识。