如何使用memcpy修改C语言循环缓冲区的入队、出队函数?
循环缓冲区入队/出队函数改用memcpy的实现方式
你的原代码中,入队和出队是直接通过结构体赋值完成的(cb->buffer[cb->tail] = data 和 PORT_ARxFrame_t data = cb->buffer[cb->head]),对于POD类型的结构体,用memcpy()实现是完全等价的,只需要明确拷贝的目标地址、源地址以及结构体的字节大小即可。
修改后的入队(enqueue)函数
int enqueue(CircularBuffer *cb, const PORT_ARxFrame_t *data) { if (is_full(cb)) { // 覆盖最旧数据 cb->head = (cb->head + 1) % BUFFER_SIZE; } else { cb->count++; } // 用memcpy将data拷贝到缓冲区的tail位置 memcpy(&cb->buffer[cb->tail], data, sizeof(PORT_ARxFrame_t)); cb->tail = (cb->tail + 1) % BUFFER_SIZE; return 1; // 成功 }
这里做了实用优化:把入参从PORT_ARxFrame_t data改成const PORT_ARxFrame_t *data,避免结构体传参的拷贝开销,同时用const修饰保证源数据不会被修改,更符合C语言开发的最佳实践。
修改后的出队(dequeue)函数
int dequeue(CircularBuffer *cb, PORT_ARxFrame_t *out_data) { if (is_empty(cb)) { // 队列为空时返回错误,同时清空输出结构体 memset(out_data, 0, sizeof(PORT_ARxFrame_t)); return 0; // 返回0表示失败 } // 用memcpy将缓冲区head位置的数据拷贝到输出参数 memcpy(out_data, &cb->buffer[cb->head], sizeof(PORT_ARxFrame_t)); cb->head = (cb->head + 1) % BUFFER_SIZE; cb->count--; return 1; // 返回1表示成功 }
同样做了优化:原函数返回结构体,当结构体较大时会有额外拷贝开销,改用输出参数out_data的方式更高效,同时通过返回值明确表示操作是否成功,比返回空结构体的方式逻辑更清晰。
关键注意点
memcpy()的第三个参数必须是sizeof(PORT_ARxFrame_t),确保整个结构体的所有成员(包括Frame和Identifier数组)都被完整拷贝。- 如果坚持保留原函数的参数/返回值形式,也可以直接替换赋值语句为memcpy,比如原enqueue可以改成:
但这种方式仍会存在结构体传参的拷贝开销,不如指针版本高效。int enqueue(CircularBuffer *cb, PORT_ARxFrame_t data) { if (is_full(cb)) { cb->head = (cb->head + 1) % BUFFER_SIZE; } else { cb->count++; } memcpy(&cb->buffer[cb->tail], &data, sizeof(PORT_ARxFrame_t)); cb->tail = (cb->tail + 1) % BUFFER_SIZE; return 1; }
完整修改后代码
#define BUFFER_SIZE 8 #define MAX_PORT_A_RX_FRAME_SIZE 200 #define MAX_PORT_A_RX_FRAME_ID_SIZE 15 #include <string.h> // 必须包含memcpy和memset的头文件 #include <stdint.h> typedef struct { unsigned char Frame[MAX_PORT_A_RX_FRAME_SIZE]; unsigned char Identifier[MAX_PORT_A_RX_FRAME_ID_SIZE]; uint8_t Size; uint8_t IdentifierSize; } PORT_ARxFrame_t; typedef struct { PORT_ARxFrame_t buffer[BUFFER_SIZE]; uint8_t head; uint8_t tail; uint8_t count; } CircularBuffer; void init(CircularBuffer *cb) { cb->head = 0; cb->tail = 0; cb->count = 0; } int is_empty(CircularBuffer *cb) { return (cb->count == 0); } int is_full(CircularBuffer *cb) { return (cb->count == BUFFER_SIZE); } int enqueue(CircularBuffer *cb, const PORT_ARxFrame_t *data) { if (is_full(cb)) { // 覆盖最旧数据 cb->head = (cb->head + 1) % BUFFER_SIZE; } else { cb->count++; } memcpy(&cb->buffer[cb->tail], data, sizeof(PORT_ARxFrame_t)); cb->tail = (cb->tail + 1) % BUFFER_SIZE; return 1; // 成功 } int dequeue(CircularBuffer *cb, PORT_ARxFrame_t *out_data) { if (is_empty(cb)) { memset(out_data, 0, sizeof(PORT_ARxFrame_t)); return 0; // 失败 } memcpy(out_data, &cb->buffer[cb->head], sizeof(PORT_ARxFrame_t)); cb->head = (cb->head + 1) % BUFFER_SIZE; cb->count--; return 1; // 成功 }
内容的提问来源于stack exchange,提问作者JGS96
相关产品推荐
相关产品推荐

