[英]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.