2011-08-24 100 views
0

我已經看到了下面的實現循環緩衝區:問題有關C實現循環緩衝區的

http://en.wikipedia.org/wiki/Circular_buffer

/**< Buffer Size */ 
#define BUFFER_SIZE 10 
#define NUM_OF_ELEMS (BUFFER_SIZE-1) 

/**< Circular Buffer Types */ 
typedef unsigned char INT8U; 
typedef INT8U KeyType; 
typedef struct 
{ 
    INT8U writePointer; /**< write pointer */ 
    INT8U readPointer; /**< read pointer */ 
    INT8U size;   /**< size of circular buffer */ 
    KeyType keys[0]; /**< Element of circular buffer */ 
} CircularBuffer; 

/**< Init Circular Buffer */ 
CircularBuffer* CircularBufferInit(CircularBuffer** pQue, int size) 
{ 
    int sz = size*sizeof(KeyType)+sizeof(CircularBuffer); 
    *pQue = (CircularBuffer*) malloc(sz); 
    if(*pQue) 
    { 
     printf("Init CircularBuffer: keys[%d] (%d)\n", size, sz); 
     (*pQue)->size=size; 
     (*pQue)->writePointer = 0; 
     (*pQue)->readPointer = 0; 
    } 
    return *pQue; 
} 

int main(int argc, char *argv[]) 
{ 
    CircularBuffer* que; 
    KeyType a = 101; 
    int isEmpty, i; 

    CircularBufferInit(&que, BUFFER_SIZE); 
    ... 
} 

這裏有幾個問題:

Q1>爲什麼代碼使用下面一行定義變量

KeyType keys[0]; /**< Element of circular buffer */ 

Q2>爲什麼代碼計算所分配的緩衝區的大小如下:

int sz = size*sizeof(KeyType)+sizeof(CircularBuffer); 

Q3>爲什麼pQue指向比環形緩衝區的尺寸大的緩衝器,但仍然可以 直接指它的成員?

(*pQue)->size=size; 
(*pQue)->writePointer = 0; 
(*pQue)->readPointer = 0; 

回答

2

第一項只是指定結構中的元素使用數組語法,但實際上沒有聲明爲任何大小的數組。

malloc分配循環緩衝區大小(佔所有非關鍵字段)和關鍵字段(大小* sizeof(KeyType))。請注意,鍵[0]的大小實際上是零,因此沒有鍵字段會被計數兩次。

緩衝區實際上不大於循環緩衝區的大小,分配(如上所述)是一次性分配以容納循環緩衝區和控制元素(size,readPointer,writePointer)通過。

這個工作的全部原因是因爲C不檢查是否走出數組的末尾。在強制實現數組邊界的語言中,當您第一次嘗試使用它時,您會得到類似於Java的ArrayOutOfBoundsException的內容,因爲要使用鍵[0],您必須聲明大小(至少)爲1的鍵數組,像鍵[1]。

換句話說,這是一些C特定的黑客優化緩衝區分配一次,而不編碼一個固定的大小。它工作的原因是因爲數組偏移嚴格實現爲(基地址+索引* sizeof(數組類型))。

+0

非常感謝:) – q0987

1
int sz = size*sizeof(KeyType)+sizeof(CircularBuffer); 

大小=在循環緩衝器元素的數目

的sizeof(關鍵字類型)=單個關鍵字類型元件

(尺寸*的sizeof)=的空間總量,用於存儲所有的尺寸KeyType元素

sizeof(CircularBuffer)=因爲循環緩衝區存儲比循環緩衝區元素更多的字段

爲什麼代碼使用以下行來定義變量鍵?

KeyType keys [0];/** <循環緩衝區的元素*/

我不明白你在這裏的疑惑。這很常見。循環緩衝區由類型爲KeyType的元素數組表示。 如果你想知道爲什麼它使用關鍵字類型,而不是直接unsigned int類型是因爲:

  1. 這樣,它更清楚。新的類型明確地告訴我們該數組是什麼。
  2. 重構目的:如果我們決定改變KeyType的類型,我們可以修改typedef。
+0

我的問題是關於'keys [0]'爲什麼0 array – q0987

+0

看起來'keys'被用作連續內存塊的頭部。 – q0987

1

發生什麼事情是在內存塊開始時有一個「頭」結構,隨後是可變數量的「細節」結構。過去,這是過去常見的做事方式;你可以通過一次調用malloc()來創建所有的結構,所以它對性能有好處。您可能還會經常使用文件處理代碼或網絡協議來查看這種模式,您將在其中獲得可變大小的數據塊,其數據的精確大小在標題中給出。 (兩者的Excel BIFF格式和TCP

1:用於被指定在一個結構的端部的可變長度數組的常用方法的零長度的數組

2:據分配的sizeof(環形緩衝區)字節和size * sizeof(KeyType),這樣就可以有很多KeyTypes,最後只有一個內存塊,它包含頭文件和密鑰文件

3:沒有指向錯誤如果它指向分配區域的外部,那將是不好的,但它不是。

+0

我覺得我有問題要理解編譯器如何通過'KeyType'的'size'連接鍵[0]。 – q0987

+0

它不。鍵[0]僅僅是給定的CircularBuffer的「真實」,非數組成員之後的地址。如果爲CircularBuffer分配sizeof(CircularBuffer)+ sizeof(KeyType)字節,那麼只有一個KeyType存在,並且緊接在內存中的CircularBuffer後面,您可以通過pCircularBuffer-> keys [0]訪問它。如果您分配sizeof(CircularBuffer)+ 10 * sizeof(KeyType)字節,將會有10個KeyType的空間,並且pCircularBuffer-> keys [0]至pCircularBuffer-> keys [9]將會有效。它有助於在交互式調試器中試用並觀察它的發生。 – mjfgates

1

此代碼imp有時稱爲「有彈性的陣列」。目標是在編譯時不知道數組的大小時創建一個包含數組的結構。所以結構被定義爲一個零大小的數組作爲最後一個元素。分配時,將所需大小添加到malloc調用中。由於C保證malloc'd塊是連續的,並且因爲它不進行數組邊界檢查,所以可以將過去的0索引到額外的內存中,並將其視爲常規數組元素。

請注意,這種技術只適用於你的malloc結構。如果它被聲明爲局部變量,那麼陣列將沒有額外的空間。