嵌入式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




