天天看點

C 語言通用模闆隊列

前言

嵌入式開發過程中,各個子產品之間,各個裝置之間進行互動時,都會存在資料的輸入輸出,由于處理的方式不同,資料不會立即同步處理,是以通常在設計時都會設計緩沖區進行資料的處理,方式資料丢失等問題;一個項目中存在不同子產品都需要緩沖區的設計,設計政策基本都一樣,不同的是資料結構,在 C 語言中可以編寫緩沖區功能函數,入參類型通常為無類型指針,适配所有需要儲存的不同資料結構,但是這種方式必須先知道不同資料結構體的大小,在寫入和讀取時按一個個位元組操作。

下面介紹的是使用宏定義函數實作該方式,按照資料結構的形式指派速度快,效率高,但是需要一定記憶體(宏定義),以空間換時間。

實作方式

宏定義函數實作資料隊列的功能,适用不同資料結構,類似于 C++ 的模闆方式,相同的實作邏輯,不同的資料結構。

點選檢視代碼

/**
  * @brief  緩存區操作資訊結構體定義
  */
typedef struct{
    uint8_t  state;         /*!< 控制狀态 */
    
    uint8_t  end;           /*!< 循環隊列尾哨兵 */
    
    uint8_t  head;          /*!< 循環隊列首哨兵 */
    
    uint8_t  num;           /*!< 循環隊列中能存儲的最多組數 */
} QueueCtrl_t;

#define QUEUE_ENABLE_COVER      (0X80)
#define QUEUE_EXIT_DATA         (0X01)
#define QUEUE_DATA_FULL         (0X02)
#define QUEUE_DATA_LOCK         (0X04)

/**
  * @brief      隊列控制初始化
  * 
  * @param[in,out]  ctrl - 隊列控制句柄
  * @param[in]  num - 隊列數目大小
  * @param[in]  cover - 0,不覆寫; 1,隊列滿了覆寫頂端資料
  */
#define QUEUE_INIT(ctrl, maxNum, cover)  ({\
    ctrl.end    = 0;\
    ctrl.head   = 0;\
    ctrl.num    = (maxNum);\
    ctrl.state  = 0x00;\
    ctrl.state  |= ((cover) ? QUEUE_ENABLE_COVER : 0);\
})

/**
  * @brief      在隊列末尾加入新的資料
  * 
  * @param[in,out]  dstLists - 隊列緩存區
  * @param[in]      src - 新的資料
  * @param[in,out]  ctrl - 隊列控制句柄
  * @retval     傳回的值含義如下
  *             @arg 0: 寫入成功
  *             @arg -1: 寫入失敗
  */
#define QUEUE_PUSH_DATA(dstLists, src, ctrl)  ({ \
    int ret = 0;\
\
    if (QUEUE_DATA_LOCK != ((ctrl.state) & QUEUE_DATA_LOCK))  \
    {\
        dstLists[(ctrl.end)++] = src;\
        (ctrl.state) |= QUEUE_EXIT_DATA;  \
\
        if ((ctrl.end) >= (ctrl.num))\
        {\
            (ctrl.end) = 0;\
        }\
\
        if (((ctrl.state) & QUEUE_DATA_FULL) == QUEUE_DATA_FULL)\
        {\
            (ctrl.head) = (ctrl.end);\
        }\
        else if ((ctrl.end) == (ctrl.head))\
        {\
            (ctrl.state) |= QUEUE_DATA_FULL;\
\
            if ((ctrl.state & QUEUE_ENABLE_COVER) != QUEUE_ENABLE_COVER)     \
            {\
                (ctrl.state) |= QUEUE_DATA_LOCK;\
            }\
        }\
\
        ret = 0;\
    }\
    else\
    {\
        ret = -1;\
    }\
\
    ret;\
})

/**
  * @brief      在隊列頂端讀取資料
  * 
  * @param[in,out]  dstLists - 隊列緩存區
  * @param[out]     dst - 讀取的資料
  * @param[in,out]  ctrl - 隊列控制句柄
  * @retval     傳回的值含義如下
  *             @arg 0: 讀取成功
  *             @arg -1: 讀取失敗
  */
#define QUEUE_POP_DATA(dstLists, dst, ctrl)  ({\
\
    int ret = -1;\
\
    if (((ctrl.state) & QUEUE_EXIT_DATA) == QUEUE_EXIT_DATA)\
    {\
        dst = dstLists[ctrl.head++];\
\
        if ((ctrl.head) >= (ctrl.num))\
        {\
            ctrl.head = 0;\
        }\
\
        if ((ctrl.head) == (ctrl.end))\
        {\
            if (((ctrl.state) & QUEUE_DATA_FULL) != QUEUE_DATA_FULL)\
            {\
                (ctrl.state) &= ~QUEUE_EXIT_DATA;\
            }\
        }\
\
        ret = 0;\
    }\
\
    (ctrl.state) &= ~QUEUE_DATA_LOCK;\
    (ctrl.state) &= ~QUEUE_DATA_FULL;\
\
    ret;\
})           

Demo測試代碼