开源仓库:unittest
基本概念
循环队列是对普通顺序队列的优化版,核心是把存储数据的数组「首尾相连」,形成一个环形的缓冲空间(就像把奶茶店的直线排队区弯成一个圆圈),解决普通顺序队列的「假溢出」问题。

上图演示中,共有8个人,当排到位置7时,发现位置0的人已经走了,空了一段时间了。那么这时候新来的8号顾客就可以站到位置0处。tail = (tail + 1) % 8 = 0; head = (head + 1) % 8 = 1。tail显示了pop(出队)后的变化,head显示的是push(入队)后的变化。
一个实例
- queue_circle.h
头文件定义的queue_frame是一个稍复杂的数据结构体,这样更符合实际项目开发需求。如果只是单纯学习循环队列原理,可以将 其理解为一个数据体,不用过多关注。重点是queue_frame_circlebuf结构体的定义。
c
#ifndef __QUEUE_CIRCLE_H
#define __QUEUE_CIRCLE_H
#ifdef __cplusplus
extern "C" {
#endif
struct queue_frame {
int id;
int len;
int flags;
int __reserved0;
int __reserved1;
int data[64];
};
// 通用环形缓冲区(队列)结构体及操作函数
#define CIRCLE_BUF_SIZE 32
struct queue_frame_circlebuf {
struct queue_frame buf[CIRCLE_BUF_SIZE];
int head;
int tail;
//int ready;
int size;
};
int queue_cbuf_is_empty(const struct queue_frame_circlebuf *cbuf);
int queue_cbuf_is_full(const struct queue_frame_circlebuf *cbuf);
int queue_cbuf_push(struct queue_frame_circlebuf *cbuf,
const struct queue_frame *frame);
int queue_cbuf_pop(struct queue_frame_circlebuf *cbuf,
struct queue_frame *frame);
#ifdef __cplusplus
}
#endif
#endif /* __QUEUE_CIRCLE_H */
- queue_circle.c
循环队列逻辑实现代码重点实现了队空、队满、入队、出队。需要注意的是这里和顺序队列的逻辑区别。循环队列通过头尾指针对最大元素数量(CIRCLE_BUF_SIZE)取余操作,实现循环。
c
#include "queue_circle.h"
#include <string.h>
/**
* ************************************************
* @brief 头地址等于尾地址,则队列为空
* @param cbuf Param...
* @return int
* ************************************************
*/
int queue_cbuf_is_empty(const struct queue_frame_circlebuf *cbuf) {
return cbuf->head == cbuf->tail;
}
/**
* ************************************************
* @brief 循环队列中剩余1个空位置时,则队列为满
* @param cbuf Param...
* @return int
* ************************************************
*/
int queue_cbuf_is_full(const struct queue_frame_circlebuf *cbuf) {
return ((cbuf->head + 1) % CIRCLE_BUF_SIZE) == cbuf->tail;
}
/**
* ************************************************
* @brief 将数据*frame插入队列
* @param cbuf Param...
* @param frame Param...
* @return int
* ************************************************
*/
int queue_cbuf_push(struct queue_frame_circlebuf *cbuf,
const struct queue_frame *frame) {
if (queue_cbuf_is_full(cbuf)) {
return -1; // 满
}
memcpy(&cbuf->buf[cbuf->head], frame, sizeof(struct queue_frame));
cbuf->head = (cbuf->head + 1) % CIRCLE_BUF_SIZE;
//cbuf->ready = 1;
cbuf->size++;
return 0;
}
/**
* ************************************************
* @brief 将数据*frame弹出队列
* @param cbuf Param...
* @param frame Param...
* @return int
* ************************************************
*/
int queue_cbuf_pop(struct queue_frame_circlebuf *cbuf,
struct queue_frame *frame) {
if (queue_cbuf_is_empty(cbuf)) {
//cbuf->ready = 0;
return -1; // 空
}
memcpy(frame, &cbuf->buf[cbuf->tail], sizeof(struct queue_frame));
cbuf->tail = (cbuf->tail + 1) % CIRCLE_BUF_SIZE;
cbuf->size--;
//if (cbuf->tail == cbuf->head) {
//cbuf->ready = 0;
//}
return 0;
}
实例测试
基于GoogleTest单元测试框架对循环队列实现逻辑进行测试分析,能够清晰的理解代码运行逻辑。
c
#define GOOGLE_GLOG_DLL_DECL
#define GLOG_NO_ABBREVIATED_SEVERITIES
#define GLOG_EXPORT
#define GLOG_NO_EXPORT
#include <gtest/gtest.h>
#include <gtest/stub.h>
#include <glog/logging.h>
#include <iostream>
#include "queue_circle.h"
using namespace std;
using namespace std::chrono_literals;
/*-----------------BEGIN----------------*/
/**
* ************************************************
* @brief 循环队列测试函数
* @return int
* ************************************************
*/
int queue_circle_main(void)
{
queue_frame_circlebuf q[8] = {0};
queue_frame frame[4] = {
{0x01, 0x0A, 0x55, 0x00, 0x00, 0x10, 0x11, 0x12},
{0x02, 0x0B, 0x55, 0x00, 0x00, 0x13, 0x14, 0x15},
{0x03, 0x0C, 0x55, 0x00, 0x00, 0x16, 0x17, 0x18},
{0x00}
};
queue_cbuf_push(&q[0], &frame[0]);
LOG(INFO) << "the queue data value: " << "0x" << std::hex << q[0].buf[0].data[0];
LOG(INFO) << "the queue size: " << "0x" << std::hex << q[0].size;
queue_cbuf_push(&q[0], &frame[1]);
queue_cbuf_push(&q[0], &frame[2]);
LOG(INFO) << "the queue data value: " << "0x" << std::hex << q[0].buf[0].data[0];
LOG(INFO) << "the queue data value: " << "0x" << std::hex << q[0].buf[1].data[0];
LOG(INFO) << "the queue data value: " << "0x" << std::hex << q[0].buf[2].data[1];
LOG(INFO) << "the queue size: " << "0x" << std::hex << q[0].size;
LOG(INFO) << "the frame data value: " << "0x" << std::hex << frame[3].data[0];
queue_cbuf_pop(&q[0], &frame[3]);
LOG(INFO) << "the frame data value: " << "0x" << std::hex << frame[3].data[0];
LOG(INFO) << "the queue size: " << "0x" << std::hex << q[0].size;
queue_cbuf_push(&q[1], &frame[0]);
queue_cbuf_push(&q[2], &frame[0]);
LOG(INFO) << "the queue data value: " << "0x" << std::hex << q[1].buf[0].data[0];
LOG(INFO) << "the queue data value: " << "0x" << std::hex << q[2].buf[0].data[0];
return 0;
}
TEST(TestSuite0, TEST3){
LOG(INFO) << "\r\nUT >>> queue_circle_main";
queue_circle_main();
}
/*------------------END-----------------*/
int gtest_main(int argc, char *argv[]){
google::InitGoogleLogging("UNITTEST");
google::SetStderrLogging(google::GLOG_INFO);
google::SetLogDestination(google::GLOG_INFO, ".//log//INFO_");
google::EnableLogCleaner(2);
//init global variable
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
google::ShutdownGoogleLogging();
}
测试报告
测试报告基于GoogleLog生成。通过查看测试报告和上面的测试case,相信读者一定你能对循环队列的代码实现有深入的理解。
powershell
Log file created at: 2026/02/12 18:04:27
Running on machine: DESKTOP-J6Q1P85
Running duration (h:mm:ss): 0:00:00
Log line format: [IWEF]yyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg
I20260212 18:04:27.791738 13304 test_case.cpp:102]
UT >>> queue_circle_main
I20260214 10:39:15.203192 15320 test_case.cpp:88] the queue data value: 0x10
I20260214 10:39:15.203192 15320 test_case.cpp:89] the queue size: 0x1
I20260214 10:39:15.204190 15320 test_case.cpp:92] the queue data value: 0x10
I20260214 10:39:15.204190 15320 test_case.cpp:93] the queue data value: 0x13
I20260214 10:39:15.204190 15320 test_case.cpp:94] the queue data value: 0x17
I20260214 10:39:15.204190 15320 test_case.cpp:95] the queue size: 0x3
I20260214 10:39:15.204190 15320 test_case.cpp:96] the frame data value: 0x0
I20260214 10:39:15.204190 15320 test_case.cpp:98] the frame data value: 0x10
I20260214 10:39:15.204190 15320 test_case.cpp:99] the queue size: 0x2
I20260214 10:39:15.204190 15320 test_case.cpp:102] the queue data value: 0x10
I20260214 10:39:15.204190 15320 test_case.cpp:103] the queue data value: 0x10