可以使用预处理器函数来定义多个预处理器宏吗?

时间:2015-05-03 14:12:44

标签: c embedded c-preprocessor microcontroller

是否可以创建预处理器函数,以便定义多个其他预处理器宏?

我正在使用微控制器框架,需要制作一些宏才能使通用中断处理程序正常运行:

<MODULE_NAME>_IRQ_PIN         //ex: PORTB_PIN(0)
<MODULE_NAME>_IRQ_IN_REGISTER //ex: GPIO_PBIN
<MODULE_NAME>_IRQ_NUMBER      //ex: GPIO_IRQA
<MODULE_NAME>_IRQ_INTCFG_REG  //ex: GPIO_INTCFGA

我试图从实现的角度来看这个过程更通用,更容易。这些宏中大约有十个需要定义,但是当给定1)端口名称2)引脚号和3)IRQ名称时,它们的定义都可以导出。我希望然后创建一个预处理器函数,它将导致生成所有这些宏。类似的东西:

#define MAKE_INTERRUPT_MACROS(module, port, pin, irq_num) \
    #define module##_IRQ_pin         PORT##port##_PIN(##pin##) \
    #define module##_IRQ_IN_REGISTER GPIO_P##port##IN \
    #define module##_IRQ_NUMBER      GPIO_IRQ##irq_num \
    #define module##_IRQ_INTCFG_REG  GPIO_INTCFG##irq_num

是否有合法的方法让预处理器执行上述操作,其中单个预处理器函数会根据传递给函数的参数生成多个其他宏?

3 个答案:

答案 0 :(得分:1)

我认为这种经典方案可以解决您的问题。这是一种简单明了的方法:

#ifdef CPU_X
#define IRQ_PIN              0
#define IRQ_IN_REGISTER      3
#define IRQ_NUMBER           11
#define IRQ_INTCFG_REG       12 
#endif

#ifdef CPU_YY
#define IRQ_PIN         PORTB_PIN(1)
#define IRQ_IN_REGISTER GPIO_PBIN(6)
#define IRQ_NUMBER      GPIO_IRQA(9)
#define IRQ_INTCFG_REG  GPIO_INTCFGA(0xA)
#endif

#ifdef CPU_KK
/* .
   . Another CPU
   .
*/
#endif

#ifdef CPU_K2
/* .
   . Another CPU
   .
*/
#endif

您可以使用-D CPU_xx编译指定CPU的代码,并解决问题!

我假设您可能有其他一些宏(E.G。:GPIO_IRQA(9)),而在CPU_YY中我已经使用过它,但它也可能用于其他CPU。

答案 1 :(得分:0)

如果您可以使用C ++而不是C,请查看使用类,每个CPU类型一个,并简单地使用类中的常量和接口。然后,你甚至不关心它们是不同的,只需使用相同的名称来访问它们(区分是根据实例化的类完成的。

如果你真的必须使用C(例如编写设备驱动程序),你可以使用方法设备驱动程序编写者使用(所有版本的* nix,VxWorks,PSOS,QNX和大多数旧的DEC OS使用这种方法,不了解Windows):只需构建一个结构,其中包含操作硬件所需的值和任何函数(或其他任何内容)。为每个硬件(或在您的情况下,模块)类型创建此结构的一个实例。然后间接通过结构。

示例:

struct module_wrapper {
    const char *module_name;
    int irq_pin;
    int irq_register;
    int irq_number;
    int irq_intcfg_reg;
    int (*init_fcn)(void);
    int (*reg_access)(int register_number);
    int (*open)(void);
    int (*close)(void);
    int (*read)(char *dst_buffer, int len);
    int (*write)(const char *src_buffer, int len);
};


 module_wrapper portB = { /* initialize here */ };
 module_wrapper gpio = { /* initialize here */ };

 printf("GPIO pin %d\n", gpio.irq_pin);

显然,根据需要进行修改。您还可以使用返回值的函数替换常量变量。

答案 2 :(得分:0)

您无法使用宏定义其他宏,但您可以通过完全相反的方式实现类似的功能。

您可以为每个可能的模块自动生成具有以下块的文件:

#ifdef <MODULE>_IRQ_DATA
#define <MODULE>_IRQ_pin         CALL(GET_IRQ_PIN, <MODULE>_IRQ_DATA)
#define <MODULE>_IRQ_IN_REGISTER CALL(GET_IRQ_IN_REGISTER, <MODULE>_IRQ_DATA)
#define <MODULE>_IRQ_NUMBER      CALL(GET_IRQ_NUMBER, <MODULE>_IRQ_DATA)
#define <MODULE>_IRQ_INTCFG_REG  CALL(GET_IRQ_INTCFG_REG, <MODULE>_IRQ_DATA)
#endif

然后:

#define CALL(MACRO, ...) MACRO(__VA_ARGS__)

#define GET_IRQ_PIN(port, pin, irq_num)         PORT##port##_PIN(pin)
#define GET_IRQ_IN_REGISTER(port, pin, irq_num) GPIO_P##port##IN
#define GET_IRQ_NUMBER(port, pin, irq_num)      GPIO_IRQ##irq_num
#define GET_IRQ_INTCFG_REG(port, pin, irq_num)  GPIO_INTCFG##irq_num

(根据定义的使用方式,您可以删除#ifdef-#endif -pairs,例如,如果所有这些都必须/可以始终定义的话)

然后实际定义所需的值只需:

#define <MODULE>_IRQ_DATA B,0,A