2015-03-13 59 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