2015-03-13 31 views
1

我有一組目標的宏對此我想基於一個選擇宏別名,像這樣的宏:C預處理產生通過串聯和字串

選擇宏:

#define I2C_MODULE 1 

別名宏(概念形式):

#define I2C_MODULE_BASE I2C<Value of I2C_MODULE>_BASE 
#define I2C_MODULE_NVIC INT_I2C<Value of I2C_MODULE> 

目標宏(從外部文件我的控制的):

#define INT_I2C0 24 
#define INT_I2C1 53 
... 
#define I2C0_BASE 0x40020000 
#define I2C1_BASE 0x40021000 
... 

我想有預處理器產生別名宏I2C_MODULE_BASE和基於I2C_MODULE_NVIC的 選擇宏I2C_MODULE,但喜歡讀Q1P1和許多其他參考資料後,我失去的,我結束了硬編碼它們的值軌道。下面我展示我當前工作的定義,然後我上次失敗的嘗試在產生宏:

什麼工作:

#define I2C_MODULE 1 
#define I2C_MODULE_BASE I2C1_BASE 
#define I2C_MODULE_NVIC INT_I2C1 

什麼沒有奏效:

#define I2C_MODULE 1 
#define STR_HELPER(x) #x 
#define STR(x) STR_HELPER(x) 

/* Attempt 1 */ 
#define I2C_MODULE_BASE "I2C" STR(I2C_MODULE) "_BASE" 
#define I2C_MODULE_NVIC "INT_I2C" STR(I2C_MODULE) 

/* Attempt 2 */ 
#define _I2C_MODULE_BASE "I2C" STR(I2C_MODULE) "_BASE" 
#define _I2C_MODULE_NVIC "INT_I2C" STR(I2C_MODULE) 
#define I2C_MODULE_BASE _I2C_MODULE_BASE 
#define I2C_MODULE_NVIC _I2C_MODULE_NVIC 

編輯:我在擴大accepted answer去我想要的地方,如下:

#define PASTE2(a, b) a ## b 
#define PASTE3(a, b, c) a ## b ## c 

#define _I2C_MODULE_BASE(x) PASTE3(I2C, x, _BASE) 
#define _I2C_MODULE_NVIC(x) PASTE2(INT_I2C, x) 

#define I2C_MODULE_BASE _I2C_MODULE_BASE(I2C_MODULE) 
#define I2C_MODULE_NVIC _I2C_MODULE_NVIC(I2C_MODULE) 
+0

什麼確切的你需要什麼?一個宏或一個字符串? – HuStmpHrrr 2015-03-13 14:16:48

+0

我不明白,你爲什麼要處理字符串?普通的'##'標識符連接應該在這裏工作得很好,但是,如果你開始嵌套這些結構,你可能會遇到評估順序的問題 – doynax 2015-03-13 14:31:21

+0

看看[C preprocessor和token concatenation](http://stackoverflow.com/問題/ 1489932/c-preprocessor-and-token-concatenation) - 它應該處理你的問題。 – 2015-03-13 14:43:10

回答

2

這似乎工作:

#define I2C_MODULE 1 

//Alias macros (conceptual form): 
//#define I2C_MODULE_BASE I2C<Value of I2C_MODULE>_BASE 
//#define I2C_MODULE_NVIC INT_I2C<Value of I2C_MODULE> 

//Target macros (from an external file out of my control): 

#define INT_I2C0 24 
#define INT_I2C1 53 

#define I2C0_BASE 0x40020000 
#define I2C1_BASE 0x40021000 

#define PASTE2(a, b) a ## b 
#define PASTE3(a, b, c) a ## b ## c 

#define I2C_MODULE_BASE(x) PASTE3(I2C, x, _BASE) 
#define I2C_MODULE_NVIC(x) PASTE2(INT_I2C, x) 

extern int i2c_module_base = I2C_MODULE_BASE(I2C_MODULE); 
extern int i2c_module_nvic = I2C_MODULE_NVIC(I2C_MODULE); 

extern int i2c_module_base_0 = I2C_MODULE_BASE(0); 
extern int i2c_module_nvic_0 = I2C_MODULE_NVIC(0); 

extern int i2c_module_base_1 = I2C_MODULE_BASE(1); 
extern int i2c_module_nvic_1 = I2C_MODULE_NVIC(1); 

樣本輸出(從cpp):

# 1 "xx.c" 
# 1 "<built-in>" 
# 1 "<command-line>" 
# 1 "xx.c" 
# 21 "xx.c" 
extern int i2c_module_base = 0x40021000; 
extern int i2c_module_nvic = 53; 

extern int i2c_module_base_0 = 0x40020000; 
extern int i2c_module_nvic_0 = 24; 

extern int i2c_module_base_1 = 0x40021000; 
extern int i2c_module_nvic_1 = 53; 

這是密切基於我的回答C preprocessor and token concatenation

有跡象表明,I2C_MODULE_BASEI2C_MODULE_NVIC宏可以寫無疑是其他方式,但關鍵點是:

  1. 使用##標記粘貼運算符(不#字符串化操作)。
  2. 使用兩級宏(例如,I2C_MODULE_BASEPASTE3)。
+0

謝謝Jonathan!它按預期工作。請看看我的OP編輯最後的用法是什麼 – 2015-03-13 15:22:56

0

只要使用#if/#else/#endif

#if (I2C_MODULE == 0) 
#define I2C_MODULE_BASE I2C0_BASE 
#define I2C_MODULE_NVIC INT_I2C0 
#elif (I2C_MODULE == 1) 
#define I2C_MODULE_BASE I2C1_BASE 
#define I2C_MODULE_NVIC INT_I2C1 
#else 
#error Unknown configuration 
#endif 
+0

這是一個簡單的方法,但當I2C_MODULE最多可以達到8時會變得很麻煩:) – 2015-03-13 15:11:52

1

我懷疑您正在編寫一個I2C驅動程序,它可以在同一個微控制器中一般處理多個I2​​C硬件外設,而無需多次重寫所有相同的代碼。

在這種情況下,你真正需要的可能是這樣的:

#define I2C1 ((volatile uint8_t*)0x12345678) // address of first hw register for I2C1 
#define I2C2 ((volatile uint8_t*)0x55555555) // address of first hw register for I2C2 

/* map all registers used for I2C, they will have same register layout for every 
    peripheral no matter which one: */ 
#define I2C_CONTROL(base) (*(base + 0)) 
#define I2C_DATA(base) (*(base + 1)) 
... 


// create some dummy typedef to make your functions look nice: 
typedef volatile uint8_t* I2C_t; 


// define whatever functions you need in the driver: 
void i2c_init (IC2_t bus); 
void i2c_send (I2C_t bus, const uint8_t* data, size_t n); 
... 

// implement functions in a bus-independent way: 
void i2c_init (IC2_t bus) 
{ 
    I2C_CONTROL(bus) = THIS | THAT; // setup registers 
} 


// caller code: 

i2c_init(I2C1); 
i2c_init(I2C2); 
... 
i2c_send(I2C1, "hello", 5); 
i2c_send(I2C2, "world", 5); 
+0

你幾乎是現貨!但問題是,這個驅動程序已經寫好了(它是德州儀器針對C的TivaWare),但其開箱即用的抽象程度還不夠高,您可以通過名稱選擇外設,並讓它執行所有必需的配置。相反,它需要你去尋找幾組相關的宏,這是我試圖通過使用選擇宏來整合的。 – 2015-03-13 15:10:38

+0

@LuisE。好吧,以上是編寫自己的驅動程序時有用的提示和技巧。 (由於TI和大多數半導體公司一樣,因其源代碼質量很差而臭名昭着,所以最終你可能最終自己寫一個......) – Lundin 2015-03-13 15:18:56