环形缓冲区莫名添加额外元素?代码问题排查求助
环形缓冲区出现未写入元素5的问题排查
问题描述
练习环形缓冲区代码时,预期缓冲区满时丢弃传入数据,但添加4个元素后,缓冲区中出现了未写入的元素5。以下是相关代码和运行输出:
示例代码
#include <stdio.h> #include <stdint.h> #include <sys/types.h> #include <unistd.h> #include <stdbool.h> #include <stdlib.h> #include <assert.h> #include <string.h> typedef struct { void *buf; ssize_t ri; //read index ssize_t wi; //write index ssize_t capacity; // total size of buffer in bytes size_t max_count; size_t count; ssize_t sz; // size of individual elements in bytes bool full; } r_buffer_t; r_buffer_t* ring_buffer_init(unsigned int count, ssize_t dsize) { r_buffer_t *buffer = malloc(sizeof(r_buffer_t)); if(buffer != NULL){ buffer->buf = malloc(count * sizeof(dsize)); if(buffer->buf != NULL) { buffer->max_count = count; buffer->sz = dsize; buffer->count = 0; buffer->ri = 0; buffer->wi = 0; buffer->capacity = count * dsize; buffer->full = false; return buffer; } free(buffer); } return NULL; } int put_item(r_buffer_t *buffer, void *data) { assert(buffer && data); // exception catch on stderr; if(!buffer->full) { printf("\nw-memcpy"); memcpy((buffer->buf + (buffer->wi * buffer->sz)), data, sizeof(buffer->sz)); printf("\n\t\tret\tdata\tcount\tfull\twi"); printf("\nAdding data :\t%d\t%d\t%ld\t%d\t%ld", 0, *((int*)data), buffer->count, buffer->full, buffer->wi); buffer->count++; buffer->wi++; buffer->wi %= buffer->max_count; if(buffer->count >= buffer->max_count) { printf("\n>>>Full for count = %ld, buffer-full = %d, index ri = %ld, wi=%ld", buffer->count, buffer->full, buffer->ri, buffer->wi); buffer->full = true; } return 0; } printf("\n>>>Dropping data. Buffer Full for count = %ld, buffer-full = %d, index ri = %ld, wi=%ld", buffer->count, buffer->full, buffer->ri, buffer->wi); return -1; } int get_item(r_buffer_t *buffer, void *data) { assert(buffer && data); if(buffer->count > 0) { printf("r-memcpy"); memcpy(data, (buffer->buf + (buffer->ri * buffer->sz)), buffer->sz); memset((buffer->buf + (buffer->ri * buffer->sz)), 0, buffer->sz); buffer->count--; buffer->ri++; buffer->ri %= buffer->max_count; buffer->full = (buffer->count >= buffer->max_count); return 0; } return -1; } void print_buffer(r_buffer_t *buffer) { int i = 0; printf("\n*************Buffer***********\n"); printf("\ncount = %ld, full = %d, ri = %ld, wi = %ld", buffer->count, buffer->full, buffer->ri, buffer->wi); printf("\n\t"); for(i =0; i < buffer->max_count; i++){ if(buffer->ri == i) printf("R "); else printf(" "); } printf("\n\t"); for(i =0; i < buffer->max_count; i++) printf("%d |", *(int *)(buffer->buf + i * buffer->sz)); printf("\n\t"); for(i =0; i < buffer->max_count; i++){ if(buffer->wi == i) printf("W "); else printf(" "); } printf("\n*********************************\n"); } int main() { int i = 0; int d1[] = {1,2,3,4,5,6,7,8,9,10}; int rd = 0; int ret = 0; r_buffer_t *buf = ring_buffer_init(5, sizeof(unsigned int)); print_buffer(buf); printf("\nAdding 4 items to buffer"); for(i = 0; i < 4; i++) { printf("\nCalling put for %d", d1[i]); ret = put_item(buf, (void *)&d1[i]); } print_buffer(buf); printf("\nRemoving and printing 2"); for(i = 0; i < 2; i++){ get_item(buf, &rd); } print_buffer(buf); printf("\nAdding 4 more items to buffer"); for(i = 4; i < 9; i++) { ret = put_item(buf, &d1[i]); } print_buffer(buf); return 0; }
运行输出
*************Buffer*********** count = 0, full = 0, ri = 0, wi = 0 R 0 |0 |0 |0 |0 | W ********************************* Adding 4 items to buffer Calling put for 1 w-memcpy ret data count full wi Adding data : 0 1 0 0 0 Calling put for 2 w-memcpy ret data count full wi Adding data : 0 2 1 0 1 Calling put for 3 w-memcpy ret data count full wi Adding data : 0 3 2 0 2 Calling put for 4 w-memcpy ret data count full wi Adding data : 0 4 3 0 3 *************Buffer*********** count = 4, full = 0, ri = 0, wi = 4 R 1 |2 |3 |4 |5 | W *********************************
问题原因及修正
1. memcpy复制长度错误(直接导致元素5出现)
在put_item函数中,memcpy的第三个参数错误使用了sizeof(buffer->sz),这会取变量buffer->sz的类型大小(ssize_t通常为8字节),而非单个元素的实际大小(buffer->sz的值,此处为4字节)。
当写入第4个元素(d1[3],值为4)时,memcpy会从&d1[3]开始复制8字节,而d1是连续存储的int数组,这会同时把d1[3](4)和d1[4](5)复制到缓冲区,覆盖了缓冲区的索引3和索引4位置,因此出现未写入的元素5。
修正代码:
memcpy((buffer->buf + (buffer->wi * buffer->sz)), data, buffer->sz);
2. 缓冲区内存分配计算错误
在ring_buffer_init函数中,内存分配时错误使用了sizeof(dsize),这会取参数dsize的类型大小(ssize_t通常为8字节),而非传入的单个元素大小(dsize的值,此处为4字节)。这会导致缓冲区分配的内存远大于实际需求,造成内存浪费,极端场景下可能引发越界问题。
修正代码:
buffer->buf = malloc(count * dsize);
内容的提问来源于stack exchange,提问作者preetam
相关产品推荐
相关产品推荐

