【问题标题】:Ring-Buffer Handler for individual types单个类型的环形缓冲区处理程序
【发布时间】:2019-07-31 06:39:00
【问题描述】:

我想构建一个环形缓冲区 API,但不是在 API 本身中使用 malloc() 动态创建缓冲区,我想传递已经存在的变量类型数组(uint8_t、uint16_t 等)。

所以我认为实现这一点的最佳方法是声明一个包含所有必需信息和所需 API 函数的结构

typedef struct ring_buffer {
    void * buffer;
    uint8_t element_size;
    size_t head;
    size_t tail;
    size_t max;
    bool full;
} ring_buffer_t;

ring_buffer_t buf_init(void * buffer, uint8_t element_size, size_t max);
void buf_add(ring_buffer_t * handle, uint8_t element);
bool buf_is_emtpy(ring_buffer_t * handle);
void* buf_pop(ring_buffer_t * handle);

ring_buffer_t buf_init(void * buffer, uint8_t element_size, size_t max){
    return (ring_buffer_t){.buffer = buffer, .element_size = 2, .head=0, .tail=0, .max=64, .full=false};
}

void buf_add(ring_buffer_t * handle, const uint8_t element){
    if(handle->head == handle->max){
        handle->head = 0;
    } 
    printf("adding %d at position %d\n", element, (uint8_t)handle->head);
    handle->buffer[handle->head] = element;
    handle->head += handle->element_size;
}

void* buf_pop(ring_buffer_t * handle){
    void* ret;
    if(handle->tail < handle->head-1){
        printf("Tail is at position %d\n", (uint8_t)handle->tail);
        ret = &handle->buffer[handle->tail];
        handle->tail += handle->element_size;
    } else {
        printf("Tail is at position %d\n", (uint8_t)handle->tail);
        ret = &handle->buffer[handle->tail];
    }
    return ret;
}

bool buf_is_emtpy(ring_buffer_t * handle){
    if(handle->head == handle->tail){
        return true;
    } else {
        return false;
    }
}

但这不起作用,因为 void* 似乎不是处理这个问题的正确方法。如何处理在创建结构时知道大小的指针?因为在 buf_add() 中,我需要将 handle-&gt;buffer 转换为正确的指针类型才能添加 element

解决此类问题的正确方法是什么?


根据给定的答案,我改变了行

handle-&gt;buffer[handle-&gt;head] = element;

memcpy(&amp;handle-&gt;buffer[handle-&gt;head], element, handle-&gt;element_size);

到目前为止,什么有效,但仍然给我一个警告,我是 dereferencing 'void *' pointer 这当然是正确的,但在这种情况下正确的取消引用会是什么样子?

【问题讨论】:

    标签: c pointers buffer


    【解决方案1】:

    看看memcpy()和朋友。由于无法提供类型时无法使用简单的赋值,因此需要复制无类型的存储块。

    请尽可能提高编译命令的警告级别。您提供的来源有一些怪癖。 ;-)

    编辑 1

    发现的怪癖:

    GCC 8.1.0(MinGW 64 位)在添加后使用-Wall -Wextra 报告的警告

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

    buf_init 有未使用的参数,element_sizemax。源使用常量。

    还有关于取消引用void* 指针和分配要添加的元素的警告。当然,因为来源并不意味着正确。

    我也会使用size_t 作为element_size 的类型,因为它代表一个大小。

    使用-pedantic GCC 会警告指针算术。但我们是故意这样做的。

    编辑 2

    关于取消引用 void* 指针的警告是正确的,所以替换每个

    &handle->buffer[offset]
    

    通过这个

    handle->buffer + offset
    

    您必须“手动”实现地址计算。

    如果您使用索引而不是偏移量,则必须乘以元素的大小:

    handle->buffer + index * handle->element_size
    

    另一个问题:memcpy() 需要一个指针作为第二个参数...这是我的建议:

    void buf_add(ring_buffer_t * handle, void *element) {
        if (handle->head == handle->max) {
            handle->head = 0;
        } 
        memcpy(handle->buffer + handle->head, element, handle->element_size);
        handle->head += handle->element_size;
    }
    

    【讨论】:

    • 你能透露这些怪癖吗? :) 我会看看我能用 memcpy 做什么,已经考虑过了,但不知何故觉得应该有更简单的方法
    • 请注意,void* 上的指针算术或解引用是非标准编译器扩展。解决方法是首先将指针转换为unsigned char *(或uint8_t *)。
    • @user694733 没错。这一变化将是朝着更好的源代码迈进的又一进步。
    猜你喜欢
    • 2012-04-04
    • 1970-01-01
    • 1970-01-01
    • 2016-12-26
    • 2021-02-20
    • 1970-01-01
    • 2018-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多