2017-06-06 137 views
3

我有這樣的一組#define語句的:我可以使用C中的宏定義宏嗎?

#define MODULE1_PINMASK 0x1 
#define MODULE2_PINMASK 0x2 
#define MODULE3_PINMASK 0x3 

其中pinmask的價值取決於第二個參數:

#define MODULE1_PORT_PIN A,1 
#define MODULE2_PORT_PIN A,2 
#define MODULE3_PORT_PIN A,3 

如果在未來任何時候,我做出改變如:

#define MODULE1_PORT_PIN A,1 /* changes to #define MODULE1_PORT_PIN A,4 */ 

我還需要改變pinmask:

#define MODULE1_PINMASK 0x1 /* then becomes #define MODULE1_PINMASK 0x4 */ 

我試圖通過不必手動更改pinmask來自動化過程。到目前爲止,我已經得到了這些宏提取MODULEX_PORT_PIN的第二個參數(我不關心在這種情況下,第一個參數):如果我在函數中使用它們

#define GET_SECOND(X, Y) Y 
#define GET_PIN(PORT_PIN) GET_SECOND(PORT_PIN) 

,我得到正確的結果,例如:

uint8_t pinmask=0x0; 

switch (GET_PIN(MODULE2_PORT_PIN)) 
{ 
    case 1: 
     pinmask = 0x1; 
     break; 
    case 2: 
     pinmask = 0x2; 
     break; 
    case 3: 
     pinmask = 0x3; 
     break; 
    default: 
     break; 
} 

printf ("%#x", pinmask); /* prints "0x2" */ 

但我想保留屏蔽爲#defines。有沒有辦法實現一個#define GET_PINMASK宏,它使用switch case來定義pinmask?我瞄準的東西是這樣的:

#define MODULE1_PINMASK ASSIGN_PINMASK(GET_PIN(MODULE1_PORT_PIN)) 

在這種情況下,將定義MODULE1_PINMASK爲0x1。

編輯:#define MODULE1_PORT_PIN A,1中的第二個參數是一個uint8_t而不是十六進制值,所以我不能直接傳遞它。

+0

在'#define MODULE1_PORT_PIN A,1'中是否有'1'(或其他什麼)被解釋爲十六進制?所以如果有'#define MODULE23_PORT_PIN A,23',那麼應該有'#define MODULE23_PINMASK 0x23'。那是對的嗎? – InternetAussie

+0

@internetAusie,該值實際上是一個uint8,所以我不能直接傳遞它。對不起,沒有澄清,我編輯了我的帖子。 – Plesos

+1

我不確定您是否知道以下事實:1.宏(with()以及without)只是宏預處理器中文本替換的主題。 2. 0x1 = 1,0x2 = 2,...,0x9 = 9.無論接受小數位數,十六進制數也是一樣(反之亦然)。 – Scheff

回答

4

我認爲你可能會過問這個問題。如果每個MODULEn_PORT_PIN的第二個字段定義始終是一個integer constant expression,那麼這應該工作:

#define MODULE1_PORT_PIN A,1 
#define MODULE2_PORT_PIN A,2 
#define MODULE3_PORT_PIN A,3 

#define GET_SECOND(X, Y) (Y) 
#define PIN_TO_MASK(PIN) (1ul << GET_SECOND(PIN)) 

#define MODULE1_PINMASK PIN_TO_MASK(MODULE1_PORT_PIN) 
#define MODULE2_PINMASK PIN_TO_MASK(MODULE2_PORT_PIN) 
#define MODULE3_PINMASK PIN_TO_MASK(MODULE3_PORT_PIN) 

它不是從你的問題的第二個字段是否可以比一個整型常量表達式以外的東西清晰。如果第二個字段涉及一個enum常量,則MODULEn_PINMASK宏仍可用於除#if表達式之外的任何上下文中。如果它涉及變量,那麼它們只能在函數體內使用。 (因爲這是C而不是C++,即使變量爲const也是如此。)

沒有辦法避免必須單獨編寫每個#define。如果這是一個問題,你應該考慮編寫一個程序來生成#define的列表。在構建時從您自己的發明的DSL生成源代碼是一種低估的技術。

+0

謝謝@zwol的工作。我讓我的生活變得困難,忽略了最簡單的方法...... – Plesos

0

您是否考慮過使用x-macros

你開始通過爲條目列表創建一個抽象#define

#define CREATE_LIST() \ 
    ENTRY(1, A, 0x1) \ 
    ENTRY(2, A, 0x2) \ 
    ENTRY(3, A, 0x3) 

,然後調用列表的ENTRY不同的定義:

// Get the number of entries. Creates something like: 
// const uint8_t PIN_COUNT = 0 + 1 + 1 + 1; 
#define ENTRY(number, x, y) + 1 
const uint8_t PIN_COUNT = \ 
    CREATE_LIST() 
; 
#undef ENTRY 

// Array of first parameters 
#define ENTRY(number, x, y) #x , 
const char * Pin_names[PIN_COUNT] = 
{ 
    CREATE_LIST() 
}; 
#undef ENTRY 

// Array of second parameters 
#define ENTRY(number, x, y) y, 
const uint8_t Pin_masks[PIN_COUNT] = 
{ 
    CREATE_LIST() 
}; 
#undef ENTRY 

// Array of module names 
#define ENTRY(number, x, y) STRINGIFY(MODULE ## number) , 
const char * Module_names[PIN_COUNT] = 
{ 
    CREATE_LIST() 
}; 
#undef ENTRY 

預處理器將擴大這有點像:

const uint8_t PIN_COUNT = 
    + 1 + 1 + 1 
; 

const char * Pin_names[PIN_COUNT] = 
{ 
    "A" , "A" , "A" , 
}; 

const uint8_t Pin_masks[PIN_COUNT] = 
{ 
    0x1, 0x2, 0x3, 
}; 

const char * Module_names[PIN_COUNT] = 
{ 
    "MODULE1", "MODULE2", "MODULE3" 
}; 

可能性我們是無止境的。它的可讀性較差,但可能稍微維護一點。

+0

X宏應該只能用作最後的手段。在這種情況下,OP需要做非常基本的工作 - 引腳數字I/O,這可以用更簡單的方法解決。這不像他們是第一個寫數字I/O的微控制器程序的人。每個端口定義一個,每個針腳掩碼一個定義對於所有這樣的程序都是足夠的。 – Lundin

+0

這只是一個建議,沒有更多,最簡單的方法已經回答了接受的答案。如果你需要更多的元數據(「命名枚舉」就是通常的例子),x宏變得有趣,因此上面的例子中的所有字符串都變得有趣。 – Groo