循环缓冲区-c

一个简单的循环缓冲区实现

com_def.h

#ifndef __COM_DEF_H__
#define __COM_DEF_H__
#include <stdint.h>
#include <stdbool.h>

typedef enum _StateFlag
{
    Off = false, On = true,
    Low = false, High = true,
    No = false, Yes = true,
    Invalid = false, Valid = true,
    Reset = false, Set = true,
    Nok = false, Ok = true,
}StateFlag;


#define RET_IF(x) if(x) return
#define RETX_IF(x, y) if(x) return (y)

#define FLAG_SET(set, flag) if(set) (flag) = Set
#define FLAG_RESET(reset, flag) if(reset) (flag) = Reset
#define FLAG_SET_REST(condition, flag) if(condition) (flag) = Set; else (flag) = Reset
#define FLAG_SET_RESET_EX(set, reset, flag) if(set) (flag) = Set; else if(reset) (flag) = Reset
#define VALUE_SET(condition, dst, value) if(condition) (dst) = (value)


#endif

circular_buffer.h

#ifndef __CIRCULAR_BUFFER_H__
#define __CIRCULAR_BUFFER_H__
#include "com_def.h"

#define CBUF_ENTITY_CNT 4

typedef struct _CircularBuffer
{
    uint8_t* buf;//数据缓冲区buf由外部提供
    uint8_t itemSize;//需要指定item的size
    uint8_t itemCntMax;//缓冲区可容纳的最大的item的counts
}CircularBuffer;


void CircularBufferCreate(const CircularBuffer* cfg, uint8_t bufId);

StateFlag CircularBufferPop(void* item, uint8_t bufId);

void CircularBufferPush(void* item, uint8_t bufId);


#endif //__CIRCULAR_BUFFER_H__

circular_buffer.c

#include "circular_buffer.h"

typedef struct _CircularBufImpl
{
    uint8_t* buf;
    uint8_t itemSize;
    uint8_t itemCntMax;
    uint8_t head;
    uint8_t tail;
    StateFlag full;
}CircularBufImpl;

#define COPY_ITEM(src, dst) do{ \
    for(uint8_t i = 0; i < p->itemSize; ++i){\
        *((uint8_t*)(dst) + i) = *((uint8_t*)(src) + i);\
    } \
}while(0)

static CircularBufImpl cBufObjs[CBUF_ENTITY_CNT] = { 0 };

void CircularBufferCreate(const CircularBuffer* cfg, uint8_t bufId)
{
    RET_IF(!cfg || !cfg->buf || !cfg->itemSize || !cfg->itemCntMax || bufId >= CBUF_ENTITY_CNT);

    cBufObjs[bufId].buf = cfg->buf;
    cBufObjs[bufId].itemSize = cfg->itemSize;
    cBufObjs[bufId].itemCntMax = cfg->itemCntMax;
    cBufObjs[bufId].head = 0;
    cBufObjs[bufId].tail = 0;
    cBufObjs[bufId].full = No;
}

void CircularBufferPush(void* item, uint8_t bufId)
{
    RET_IF(!item || bufId >= CBUF_ENTITY_CNT);

    CircularBufImpl* p = &cBufObjs[bufId];

    uint8_t* addr = p->buf + p->tail * p->itemSize;

    COPY_ITEM(item, addr);

    ++p->tail;
    p->tail %= p->itemCntMax;

    VALUE_SET(p->tail == p->head, p->full, Yes);

    if(p->full && p->tail > p->head){
        ++p->head;
        p->head %= p->itemCntMax;
    }
}

StateFlag CircularBufferPop(void* item, uint8_t bufId)
{
    RETX_IF(!item || bufId > CBUF_ENTITY_CNT, Nok);

    CircularBufImpl* p = &cBufObjs[bufId];

    RETX_IF(p->full == No && p->head == p->tail, Nok);//empty

    uint8_t* addr = p->buf + p->head * p->itemSize;

    COPY_ITEM(addr, item);

    ++p->head;
    p->head %= p->itemCntMax;

    VALUE_SET(p->head > p->tail, p->full, No);

    return Ok;
}

测试:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#include "circular_buffer.h"

typedef struct _Test
{
    uint32_t p;
    uint16_t b;
    uint8_t a;
}Test;

#define TEST_CNT 5

static void PtBuf(Test* p)
{
    for(int i = 0; i < TEST_CNT; ++i){
        printf("(% 4d,% 4d,% 4d) ", p[i].p, p[i].b, p[i].a);
    }
    printf("\n");
}

int main(void)
{
    Test buf[TEST_CNT] = { 0 };
    Test t = { 4, 1, 2 };
    Test m = { 0 };
    CircularBuffer cfg = {
        .buf = (uint8_t*)buf,
        .itemSize = sizeof(Test),
        .itemCntMax = TEST_CNT,
    };
    CircularBufferCreate(&cfg, 0);

    if(CircularBufferPop(&m, 0)){
        printf("(% 4d,% 4d,% 4d)\n",m.p, m.b, m.a);
    }


    for(uint8_t i = 0; i < 4; ++i){
        CircularBufferPush(&t, 0);
        PtBuf(buf);
        t.p++;
    }

    for(uint8_t i = 0; i < 6; ++i){
        if(CircularBufferPop(&m, 0)){
            printf("(% 4d,% 4d,% 4d)\n", m.p, m.b, m.a);
        }
    }
}
上一篇:打印图形(蓝桥杯省赛2018C/C++A组第五题) 补全填空题


下一篇:【小测试】golang中使用string()来转换[]byte数组产生了拷贝