You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

嵌入式C环形缓冲区满时清空丢失第5字节的问题求助

解决环形缓冲区跳过第5字节的问题

我来帮你分析一下代码里的问题,以及如何修复这个总是跳过第5字节的bug:

问题根源分析

1. ring_buffer_full 函数实现完全错误

你当前的ring_buffer_full函数判断逻辑完全不符合环形缓冲区的设计逻辑:

int ring_buffer_full(ring_buffer_t *c) {
 return c->head == c->maxLen ? 1 : 0;
}

它只是检查head是否等于缓冲区最大长度,和缓冲区是否已满没有任何关系,正确的满判断应该和ring_buffer_put里的逻辑对齐,或者用更直观的计数方式。

2. 主函数逻辑错误:等到缓冲区满到无法写入才处理,导致当前字节丢失

你现在的逻辑是:当ring_buffer_put返回-1(无法写入当前字节)时才清空缓冲区,但这时候当前的字节(比如i=4、i=9)根本没被写入缓冲区,直接被跳过了,这就是你丢失第5个字节的核心原因。

3. 环形缓冲区容量设计的误解

你当前的环形缓冲区用head == tail表示空,next == tail表示满,这种设计会牺牲一个字节的空间(maxLen=5时最多存4个字节),如果想存满5个字节触发清空,需要调整设计逻辑。


修复方案:改用计数式环形缓冲区(更直观且无空间浪费)

我推荐修改环形缓冲区的实现,新增一个count变量跟踪当前数据量,这样既避免空间浪费,也让判断空/满的逻辑更简单清晰。

修正后的完整代码

#include <stdio.h>
#include <stdint.h>

uint8_t outData;
uint8_t myDatBuf[32];

typedef struct {
    uint8_t * buffer;
    int head;
    int tail;
    int maxLen;
    int count; // 新增:跟踪当前缓冲区中的数据数量
} 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 ring_buffer_count(ring_buffer_t *c);

int main() {
    uint8_t a = 0;
    rb.buffer = myDatBuf;
    rb.head = 0;
    rb.tail = 0;
    rb.maxLen = 5;
    rb.count = 0; // 初始化计数

    for (uint8_t i = 0; i < 12; i++) {
        // 先尝试写入当前字节
        if (ring_buffer_put(&rb, i) == -1) {
            printf("Ring Buffer is full! Lets empty it\n\r");
            // 清空缓冲区
            while (ring_buffer_has_data(&rb)) {
                if (ring_buffer_get(&rb, &outData) == -1) {
                    printf("Buffer is Empty\n\r");
                } else {
                    printf("val: %d\n\r", outData);
                }
            }
            // 清空后重新写入当前字节
            ring_buffer_put(&rb, i);
        } else {
            // 写入成功后检查是否达到5个字节
            if (ring_buffer_count(&rb) == rb.maxLen) {
                printf("Reached %d bytes, emptying buffer\n\r", rb.maxLen);
                while (ring_buffer_has_data(&rb)) {
                    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) {
    if (c->count >= c->maxLen) {
        // 缓冲区已满,无法写入
        return -1;
    }
    c->buffer[c->head] = data;
    // 用取模简化环形指针移动
    c->head = (c->head + 1) % c->maxLen;
    c->count++;
    return 0;
}

int ring_buffer_get(ring_buffer_t *c, uint8_t *data) {
    if (c->count == 0) {
        // 缓冲区为空,无法读取
        return -1;
    }
    *data = c->buffer[c->tail];
    c->tail = (c->tail + 1) % c->maxLen;
    c->count--;
    return 0;
}

int ring_buffer_full(ring_buffer_t *c) {
    return c->count == c->maxLen;
}

int ring_buffer_has_data(ring_buffer_t *c) {
    return c->count > 0;
}

int ring_buffer_count(ring_buffer_t *c) {
    return c->count;
}

修复后的运行输出

Reached 5 bytes, emptying buffer
val: 0
val: 1
val: 2
val: 3
val: 4
Reached 5 bytes, emptying buffer
val: 5
val: 6
val: 7
val: 8
val: 9
Empty the remaining bytes
Rest: 10
Rest: 11

可以看到,现在所有字节都被正确处理,没有丢失第5个字节了。


内容的提问来源于stack exchange,提问作者PhillyNJ

火山引擎 最新活动