You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 19:53:12