c - 环形缓冲区满时清空

标签 c arrays

我正在使用环形缓冲区来跟踪嵌入式 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_puthead 等于 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/

相关文章:

c - 两个不同显示器上的两个全屏窗口

c - 在 C 中使用结构

c - 为什么我的信号处理程序执行两次?

c - Linux C 串行程序卡住

php - 在 Laravel 中检查请求数组是否为空

c - 命名管道如何识别客户端

javascript - 无法将 Google map 标记对象保存到隐藏 html 字段中的数组

arrays - Swift:通过函数更改全局变量的值。

javascript - 使用数组reduce来减少对象数组的两个属性

java - 导致我的程序在 if-else 语句后无法继续运行的字符串数组 - java