C预处理器通过串联和字符串化生成宏

我有一组目标宏,我想根据选择的宏生成别名,如下所示:

选择宏:

#define I2C_MODULE 1 

别名宏(概念forms):

 #define I2C_MODULE_BASE I2C_BASE #define I2C_MODULE_NVIC INT_I2C 

目标宏(来自我控制的外部文件):

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

我希望让预处理器根据选择的宏I2C_MODULE生成别名宏I2C_MODULE_BASEI2C_MODULE_NVIC ,但是经过多次读取Q1 , P1和许多其他参考我失去了跟踪,我最终硬编码了它们的值。 下面我展示了我当前的工作定义,然后是我上次生成宏的失败尝试:

什么有效:

 #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 

编辑:我扩展了接受的答案,以达到我想要的地方,如下:

 #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) 

这似乎有效:

 #define I2C_MODULE 1 //Alias macros (conceptual form): //#define I2C_MODULE_BASE I2C_BASE //#define I2C_MODULE_NVIC INT_I2C //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 "" # 1 "" # 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预处理器和令牌连接的回答。

毫无疑问,可以编写I2C_MODULE_BASEI2C_MODULE_NVIC宏的其他方法,但关键点是:

  1. 使用## token贴注运算符(而不是#stringifying运算符)。
  2. 使用两级宏(例如, I2C_MODULE_BASEPASTE3 )。

我怀疑你正在编写一个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); 

只需使用#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