我正在使用环形缓冲区来跟踪嵌入式 C 应用程序下载的字节。在这个小例子中,当环形缓冲区中有 5 个字节时,我想要“清空”缓冲区。在实际应用中,我将处理要写入闪存的字节。我的问题是,我一直跳过第五个字节。这是我的代码:
#include <stdio.h>
#include <stdint.h>
uint8_t outData;
uint8_t myDatBuf[32];
typedef struct {
uint8_t * buffer;
int head;
int tail;
int maxLen;
} ring_buffer_t;
ring_buffer_t rb;
int ring_buffer_get(ring_buffer_t *c, uint8_t *data);
int ring_buffer_put(ring_buffer_t *c, uint8_t data);
int ring_buffer_full(ring_buffer_t *c);
int ring_buffer_has_data(ring_buffer_t *c);
int main()
{
uint8_t a = 0;
rb.buffer = myDatBuf;
rb.head = 0;
rb.tail = 0;
rb.maxLen = 5;
for (uint8_t i = 0; i < 12; i++) {
if (ring_buffer_put(&rb, i) == -1) { // rb is full
printf("Ring Buffer is full! Lets empty it\n\r");
for (int x = 0; x < 5; x++) {
if (ring_buffer_get(&rb, &outData) == - 1) {
printf("Buffer is Empty\n\r");
} else {
printf("val: %d\n\r", outData);
}
}
}
}
printf("Empty the remaining bytes\n\r");
while (ring_buffer_has_data(&rb)) {
if (ring_buffer_get(&rb, &outData) == -1) {
printf("Buffer is Empty\n\r");
}
else {
printf("Rest: %d\n\r", outData);
}
}
return 0;
}
int ring_buffer_put(ring_buffer_t *c, uint8_t data)
{
// next is where head will point to after this write.
int next = c->head + 1;
if (next >= c->maxLen) {
next = 0;
}
if (next == c->tail) { // check if circular buffer is full
return -1;
} // and return with an error.
c->buffer[c->head] = data; // Load data and then move
c->head = next; // head to next data offset.
return 0; // return success to indicate successful push.
}
int ring_buffer_get(ring_buffer_t *c, uint8_t *data)
{
// if the head isn't ahead of the tail, we don't have any characters
if (c->head == c->tail) // check if circular buffer is empty
return -1; // and return with an error
// next is where tail will point to after this read.
int next = c->tail + 1;
if (next >= c->maxLen)
next = 0;
uint8_t t = c->tail;
*data = c->buffer[t]; // Read data and then move
c->tail = next; // tail to next data offset.
return 0; // return success to indicate successful pop.
}
int ring_buffer_full(ring_buffer_t *c) {
return c->head == c->maxLen ? 1 : 0;
}
int ring_buffer_has_data(ring_buffer_t *c) {
return (c->head != c->tail) ? 1 : 0;
}
这是输出 - 正如您所看到的,数组中的第 5 个元素被跳过。任何帮助表示赞赏。
Ring Buffer is full! Lets empty it
val: 0
val: 1
val: 2
val: 3
Buffer is Empty
Ring Buffer is full! Lets empty it
val: 5
val: 6
val: 7
val: 8
Buffer is Empty
Empty the remaining bytes
Rest: 10
Rest: 11
最佳答案
问题是 head == tail
是一个不明确的情况。这是否意味着缓冲区为空,或者是否意味着缓冲区已满?你不能两全其美。您似乎已经意识到这一点,因为 ring_buffer_put
在 head
等于 tail
之前返回错误,避免了歧义。并且ring_buffer_get还假设head == tail意味着空缓冲区。所以事实上,这样一个 maxLen == 5
的环形缓冲区只能包含 4 个元素!
那么为什么值 4
似乎丢失了?原因很简单,如果 ring_buffer_put
返回 -1
,缓冲区将被刷新,但不会再次尝试将值放入缓冲区。因此,问题不在于环形缓冲区实现本身(对我来说看起来不错),而在于 main
中驱动它的代码。
您可以通过让 ring_buffer_put
执行 put 操作来解决此问题,然后检查缓冲区是否已满。或者,您可以添加一个单独的 ring_buffer_is_full
函数,在尝试写入缓冲区之前调用该函数。
关于c - 环形缓冲区满时清空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50588299/