簡體   English   中英

C中的FIFO實現

[英]FIFO implementation in C

我正在分析一個 Inte.net 指南,我喜歡這樣的代碼。 有人可以向我解釋 ~ 和 & 運算符的用法嗎?

提前致謝

uint8_t tx_fifo_put(tx_dataType data)
{
/*Check if FIFO is full*/
    if((tx_put_itr - tx_get_itr) & ~(TXFIFOSIZE-1))
        {
            /*FIFO full - return TXFAIL*/
            return (TXFAIL);
        }

    /*Put data into fifo*/
    TX_FIFO[tx_put_itr & (TXFIFOSIZE - 1)] = data;
    /*Incerment itr*/
    tx_put_itr++;
    return(TXSUCCESS);
}

代碼的作用是用一種混淆的方式來替換更易讀的代碼。

正如評論者在我之前寫的那樣, TX_FIFO[tx_put_itr & (TXFIFOSIZE - 1)] = data; 循環輸出。 同樣正如評論中提到的那樣,代碼的大小是 2 的冪。

我不知道為什么會這樣做,對我來說TX_FIFO[tx_put_itr % TXFIFOSIZE] = data也是如此,但更具可讀性。 此外,人們希望謂詞檢查在數據訪問之前進行。 至少這是我的本性。

(w - r) &~ size部分是一種檢查(1) w < r(2)作為邊緣情況的方法, w等於FIFOSIZE並且r為零。 從語義上講,它應該意味着“如果寫指針指向邊界,而讀指針指向緩沖區的開頭,我們建議,對於我們的數據結構,下一次寫入可能是溢出。”

讓我們看看一些代碼、數字和它們的二進制表示。

let s = 8 - 1, in binary is 00000111 and negated is 11111000.
let w = 0, let r = 1.
now in binary w = 00000000, r = 00000001.
w - r = 11111111, logical and that with ~(8 - 1) and get some value, other then zero.

繼續w < r情況的邏輯,我們得到任何負整數都會在上面產生一些位。 所以這true OP if代碼肯定是正確的。

現在w = r情況不能將位提交到布爾測試。

最后一個案例,

let s = 8,
let w = 8
let r = 0

  w - r      = 00001000
~(8 - 1)     = 11111000
(w - r) &~ 7 = 00001000

w > r的所有其他情況為零。

更新

令我悲痛的是, @UkropUkraine刪除了所有評論和他的回答。 那里有一些關於可以使用(w - r) >= mask代替(w - r) & mask的事實的討論。

在這里,我提供了一個代碼,並解釋它不是優化,或者只是語法,或者編寫 OP 代碼的人想到的任何東西。 它是預期的代碼。 而且它沒有達到它的目的:作為 FIFO 或循環隊列運行,或者任何該部分代碼的目的。

首先,舉一個用法的例子。 Ukrop用戶有困難的部分。 w指針可以小於r指針。 w - r的結果將是負數。

常見的用法是向緩沖區添加一個字節,並在寫指針到達末尾時包裝寫指針。 想象一下w指針已經包裹的情況。

#include <stdio.h>

int main()
{
 unsigned char w = 0, r = 1;
 int r;
 
 r = (a - b) & 0xffffffff;
 
 printf("%d\n", r);

 return 0;
}

-1

我不知道微控制器常見的布爾結果類型是什么。 對於普通的x86 C機器,它是int 所以我希望if((w - r) &~ size)被轉換為int 結果是否定的。 您不能只使用>= 、 '>' 或==來編寫上述內容,正如評論和此處的其他答案所述。

不僅如此,代碼在語義上也失敗了。 我不知道它應該是一個 FIFO 或其他東西。 但是在上述情況下,讀指針仍然有一些有意義的數據要讀取。 並且可以這樣做,因為寫指針,即使它被包裝,也不會覆蓋緩沖區的讀取部分,但是 但代碼返回BUFFULL

我認為讀/寫是不同的方向,但它並沒有改變任何東西。 OP 給出的代碼沒有達到預期的效果。

也許我確實錯過了一些見解,作為Ukrop用戶和 OP,向我指出他們知道代碼語義的事實。 OP 只是沒有得到~&用法。 好吧,這是一個答案, ~&用於測試負值和邊緣情況。

兩個運算符:

&是位與運算符

~是按位補碼運算符

現在對於發布的代碼,重要的是要注意TXFIFOSIZE的值必須是 2 的冪,即 2、4、8、16、32 等值。

如果這是真的,代碼:

TX_FIFO[tx_put_itr & (TXFIFOSIZE - 1)] = data;

相當於:

TX_FIFO[tx_put_itr % TXFIFOSIZE] = data;

請注意, tx_put_itr的遞增方式使其值高於 TXFIFOSIZE。 因此,為了獲得有效的數組索引,代碼必須找到tx_put_itr相對於 TXFIFOSIZE 的余數。

那么它是如何工作的呢? 為什么上面的行是等價的?

讓我們以一個值為例。

Assume TXFIFOSIZE is 8 (2 to the power of 3)
So TXFIFOSIZE-1 is 7
7 is bitwise 00....00111
And when you do:
SOME_NUMBER & 00....00111
You keep the 3 least significant bits of SOME_NUMBER
And that is exactly the remainder of when diving by 8

那么讓我們來看看

if((tx_put_itr - tx_get_itr) & ~(TXFIFOSIZE-1))

它相當於

if((tx_put_itr - tx_get_itr) >= TXFIFOSIZE)

因此它會檢查“FIFO 已滿”

再次使用示例,它的工作原理如下:

Assume TXFIFOSIZE is 8 (2 to the power of 3)
So TXFIFOSIZE-1 is 7
7 is bitwise 00....00111
~7 is bitwise 11....11000
And when you do:
SOME_NUMBER & 11....11000
You clear the 3 least significant bits of SOME_NUMBER and keep the rest unchanged
So if the result is non-zero it means that the difference between 
tx_put_itr and tx_get_itr is 8 (or more).

為嵌入式 C++ 實現了基本 FIFO

// FIFO Status
#define FIFO_EMPTY                              0
#define PUSH_SUCCESS                            1
#define FIFO_OVERFLOW                           -1

/*
 * Description: A simple FIFO implementation. It is assumed that data won't contain any zeros as FIFO_EMPTY status returns 0
 */
template <typename T>
class FIFO {
    public:
        // Constructors
        FIFO(T * bufferPointer, int32_t bufferSize) : bufferPointer(bufferPointer), bufferSize(bufferSize) {
            this->head = 0;
            this->tail = 0;
        }

        virtual ~FIFO() { }

        // Core Functions
        int8_t push(T data) {
            if(isFull())
                return FIFO_OVERFLOW;

            bufferPointer[head++] = data;
            if(head >= bufferSize)
                head = 0;

            return PUSH_SUCCESS;
        }

        T pop() {
            T returnVar;

            if(isEmpty())
                return (T)FIFO_EMPTY;

            returnVar = bufferPointer[tail++];
            if(tail >= bufferSize)
                tail = 0;

            return returnVar;
        }

        inline bool isFull() { return (((head + 1) == tail) || (((head + 1) == bufferSize) && (tail == 0)) ); }
        inline bool isEmpty() { return (tail == head); }

    private:
        volatile T * const bufferPointer;
        const int32_t bufferSize;

        volatile int32_t head;
        volatile int32_t tail;
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM