【问题标题】:Can a preprocessor function be used to define multiple preprocessor macros?一个预处理器函数可以用来定义多个预处理器宏吗?
【发布时间】:2015-07-12 22:24:12
【问题描述】:

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

我正在一个微控制器框架中工作,该框架需要创建一些宏才能使通用中断处理程序起作用:

<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

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

【问题讨论】:

  • 你不能在宏中使用#define
  • 这些都是宏有必要吗?你可以将它们声明为staticconst-qualified 对象。如果定义和初始化在头文件中可见,这应该和宏一样好。
  • 预处理器被解析一次并且不是递归的,那么不可能有你写的东西。最简单的解决方案是定义您必须使用的 CPU 函数中的所有值的经典方法!

标签: c embedded c-preprocessor microcontroller


【解决方案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 的代码,问题应该得到解决!

我假设您可能有其他一些宏(例如:GPIO_IRQA(9)),并且在 CPU_YY 中我已经使用了它,但它也可能用于其他 CPU。

【讨论】:

  • 我正打算以这种方式回答一些问题。不过,我在您的答案中看不到任何“#define”,而且每行似乎有两个预处理器标识符。
  • @Gauthier。非常感谢通知! (我累了就停下来写评论:p)
【解决方案2】:

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

如果您真的必须使用 C(例如编写设备驱动程序),您可以使用设备驱动程序编写者使用的方法(所有风格的 *nix、VxWorks、PSOS、QNX 和大多数旧的 DEC 操作系统都使用这种方法,不了解 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);

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

【讨论】:

    【解决方案3】:

    你不能用一个宏定义其他宏,但是你可以通过完全相反的方式来实现类似的东西。

    您可以为每个可能的模块自动生成一个包含以下块的文件:

    #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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-29
      • 1970-01-01
      • 2011-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多