2014-10-31 87 views
1

我有一個源文件,它提供了對結構進行排隊並從數組中彈出/推送它們的功能。標題每次預處理的方式不同#include(ed)

爲簡潔起見,以下是queue.c文件的外觀示例 - 省略了一些無關的定義。

queue.c

#include <stdint.h> 
#include <stdbool.h> 
#include <stdlib.h> 
#include "queue.h" 

queue_t queueCreate (void) { 
    queue_t newQueue; 
    newQueue.state = QUEUE_EMPTY; 
    newQueue.front = 0; 
    newQueue.count = 0; 
    return newQueue; 
} 

/* 
* Returns the first in from the queue passed to it if possible 
*/ 
enum STATE_QUEUE queuePop (queue_t *queue, queueElement_t *pop) { 
    // if queue isn't empty 
    if(!queue_isEmpty(queue)) { 
     // get element at front of queue 
     (*pop) = (*queue).queue[(*queue).front]; 

     // decrease count by 1 as element has been removed from queue 
     (*queue).count--; 

     // if front needs to wrap round the array 
     if((*queue).front == (QUEUE_SIZE - 1)) { 
      (*queue).front = 0; 
     } else { 
      (*queue).front++; 
     } 

     // 
     queueState(queue); 

     // return the popped element to the calling function 
     return QUEUE_OK; 
    } 
    return QUEUE_EMPTY; 
} 

在頭文件,我宣佈某些類型和使用宏結構內改變的成員。使用此代碼時,#defines將指定這些結構中的成員。這是值得什麼,這些宏定義結構的內容不會被queue.c引用,但會被定義和使用呼叫源文件

頭看起來像這樣

queue.h

#ifndef QUEUE_SIZE 
    #define QUEUE_SIZE 10 
    #define QUEUE_COUNT_TYPE BYTE 
#else 
    #ifndef QUEUE_COUNT_TYPE 
     #if QUEUE_SIZE > 255 
      #define QUEUE_COUNT_TYPE int 
     #else 
      #define QUEUE_COUNT_TYPE BYTE 
     #endif 
    #endif 
#endif 

    /* Queued types */ 
#ifndef QUEUE_TYPE 
    #define QUEUE_TYPE struct { \ 
          int data; \ 
         } 
#endif 

    /* Queue type definitions*/ 
    typedef QUEUE_TYPE queueElement_t; 

    typedef struct { 
     QUEUE_COUNT_TYPE front; 
     QUEUE_COUNT_TYPE count; 
     queueElement_t queue[QUEUE_SIZE]; 
    } queue_t; 

    /* Function Prototypes */ 
    queue_t    queueCreate (void); 

的內調用源文件將重新定義QUEUE_TYPE以處理任何相關的結構。

我打算在我的項目的多個源文件中使用此頭文件時,將#include中的#defines用於更改queueElement_t的定義。

我會遇到類型錯誤,因爲函數名稱是相同的,但處理不同的參數類型?或者有沒有一種方法可以讓我描述這個工作?

TL; DR如果我包括遍佈整個我的項目,即使用宏來改變這種不明確的頭文件中訪問結構成員的源文件頭文件,將我遇到任何錯誤

+0

閱讀關於什麼「* Header Guards *」以及爲什麼要使用它們。 – alk 2014-10-31 17:25:26

+0

@alk謝謝,我知道標頭警衛,但不知道,如果推理仍然適用,如果我足夠小心,以避免在同一範圍內兩次定義相同的作用 – AustinGeorge 2014-10-31 22:16:03

+0

此函數:queue_t queueCreate(void){返回一個值/結構是分配在該函數的本地堆棧上。這是一個編程nono。因爲堆棧可能會損壞。更好地將函數改爲:queue_t * queueCreate(void){然後在函數內部:this:queue_t newQueue;應該是:queue_t * newQueue = malloc(sizeof queue_t);應該檢查不是NULL,然後使用格式:newQueue-> field = ..;來填寫字段。調用者現在必須期望返回一個指針而不是一個完整的queue_t結構體。 – user3629249 2014-11-01 04:37:39

回答

1

在你的具體情況中:是的。因爲你有一個功能,預計將使用某種結構作爲回報。因此,當您嘗試使用具有不同類型定義的兩個不同模塊的結構時,您會發現非常有趣的問題,與您正在使用的平臺上的ABI相關。

但是,您可以切換到只使用宏,這將更像C++中的模板。小例子:

#define QUEUE_TYPE(element, size) struct { int front, count; type queue[size]; } 
#define QUEUE_INIT(queue) queue.front = queue.count = 0; 
#define QUEUE_SIZE(queue) sizeof(queue.queue)/sizeof(queue.queue[0]) 
#define QUEUE_PUSH(queue,val) \ 
    if (queue.front < QUEUE_SIZE(queue)) queue.queue[queue.front++] = val; 
... 

struct { 
    QUEUE_TYPE(int,10) member; 
} my_var; 
... 
QUEUE_INIT(my_var.member); 
QUEUE_PUSH(my_var.member, 10) 
+0

啊,這是有道理的。當'queue.h'的不同調用永遠不在同一個範圍內時,這仍然適用嗎? – AustinGeorge 2014-10-31 22:12:39

+0

@AustinGeorge是的。因爲你定義了符號(在你的例子中是函數),在全局範圍內可見。如果你所有的函數都在頭文件中定義爲靜態,全局符號將被刪除,但是仍然有可能在模塊範圍內多次重新定義宏。 – 2014-11-01 12:50:24

+0

謝謝。我認爲這是因爲我以前只使用過c的pic微處理器,所以缺乏關注範圍的經驗。爲了讓我的頭部四捨五入,我可以將所有元素處理邏輯從調用模塊移動到隊列模塊,以便允許隊列模塊的調用之間的隊列元素結構差異?另外,爲了在元素彈出時保持相同的功能,id需要能夠在全局範圍內更改變量。我想我可以用指向每個元素的指針來完成這些全局變量嗎? – AustinGeorge 2014-11-02 16:44:17

相關問題