【问题标题】:Use specific entry of an X macro使用 X 宏的特定条目
【发布时间】:2020-10-09 08:35:32
【问题描述】:

我正在使用 X 宏生成将 GPIO 设置为 01 的函数(我生成了大约 60 个函数来设置大约 30 个 GPIO)。下面是一个例子(这个例子我刚刚写过,所以语法可能有误):

/* X(pin_name, pin_nb) */
#define CPLD_GPIOs \
  X(Pin0, 0) \
  X(Pin1, 1) \
  X(Pin2, 2) \
  X(Pin3, 3)

我生成访问这些 GPIO 的函数:

#define X(pin_name, pin_nb) \
  static void SetOn_GPIO##pin_name (void) { \
    SetOn_GPIOpins(pin_nb);\
    }
    CPLD_GPIOs
#undef X

SetOff_GPIOXXX 函数存在相同的过程。

有没有一种方法可以在程序的其他部分以SetOn_GPIOPin2 的形式访问上面由编译器生成的函数,而无需直接编写函数名? (为了使代码尽可能全局化)

在预处理结束时,我们应该只从 X-Macro 生成 SetOn_GPIOPin2();(而不是每个 X-macro 条目)。

预处理前:

void foo ()
{
  /* some code */

  /* 
   * Macro to generate the desired function.
   * For e.g: SetOn_GPIOPin2();
   */

  /* some code */
}

预处理后:

void foo ()
{
  /* some code */

  /* Function resulting of the pre-processing */
  SetOn_GPIOPin2();

  /* some code */
}

【问题讨论】:

  • 为什么不能只写SetOn_GPIOPin2();
  • @mkrieger1 :我可以写SetOn_GPIOPin2(),但如果有人或我决定更改X-Macro 定义中的引脚名称,我应该更改对这个函数的每次调用。

标签: c macros x-macros


【解决方案1】:

从问题的 cmets 来看,您的目标似乎是防止您的 X 宏被修改以产生不同名称的函数的情况。如果是这样,那么我认为您正在为自己做不必要的工作:这些名称是否被更改是在您(以及任何其他项目开发人员)的控制之下,并且您担心的名称更改不会被忽视很长时间.所以不要改变它们

但是,如果您决定走这条路,那么不,没有办法让预处理器从较大的替换文本中提取宏生成的函数名称。相反,您需要通过相同的宏将它们注入到 X 宏和您的其他代码中。像这样,也许:

/* X(pin_name, pin_nb) */
#define CPLD_GPIOs(gen) \
  X(Pin0, 0, gen) \
  X(Pin1, 1, gen) \
  X(Pin2, 2, gen) \
  X(Pin3, 3, gen)

// Generates the wanted function names:
#define GPIO_ON(pin_name, pin_nb) SetOn_GPIO##pin_name

#define X(pin_name, pin_nb, gen) \
  static void gen(pin_name, pin_nb) (void) { \
    SetOn_GPIOpins(pin_nb);\
    }
    CPLD_GPIOs
#undef X

// ...

void some_function(void) {
    GPIO_ON(pin_name, pin_nb)();
}

但请注意,尽管此技术可能还有其他应用,例如使用同一组 X 宏生成多组函数,但它只是针对您所描述的特定目标将罐头推向了道路。您可以依赖 name-generator 宏为函数声明和函数调用生成相同的名称,但您仍然存在一个问题,即可以修改 X 宏以生成具有不同名称的函数声明。

【讨论】:

    【解决方案2】:

    使用我们值得信赖的 Boost.Preprocessor 火箭发射器,这非常简单:

    #include <boost/preprocessor/tuple/rem.hpp>
    #include <boost/preprocessor/control/if.hpp>
    #include <boost/preprocessor/comparison/equal.hpp>
    
    #define X_SELECT_PIN(pin_nb, selected_pin_nb, ...)  \
      BOOST_PP_TUPLE_REM_CTOR(BOOST_PP_IF(              \
        BOOST_PP_EQUAL(pin_nb, selected_pin_nb),        \
        (__VA_ARGS__),                                  \
        ()                                              \
      ))
    
    
    // Usage
    
    #define X(pin_name, pin_nb)\
      X_SELECT_PIN(pin_nb, 2, SetOn_GPIO##pin_name (void);)
      CPLD_GPIOs
    #undef X
    

    这使用BOOST_PP_IF 仅针对所选引脚扩展您的模式。添加的括号和BOOST_PP_TUPLE_REM_CTOR 用于保护宏免受包含逗号的扩展。

    【讨论】:

    • 谢谢你的回答,我不知道Boost.Preprocessor,我去看看。
    • Boost 是一个 C++ 库,但问题标记为 C。
    • @JohnBollinger 不是。来自its documentation:“该库支持 C++ 和 C 编译。它不依赖于任何其他 Boost 库,因此可以用作独立库。”
    • 可能 Boost.Preprocessor 特别支持 C 和 C++,这肯定是相关的。但如果是这样,那么在 Boost 模块中是非常不寻常的。总体而言,Boost 是特定于 C++ 的。主要是模板。
    • @JohnBollinger 是的,我的意思是 Boost.Preprocessor,我的错。
    猜你喜欢
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-16
    • 2021-07-05
    • 1970-01-01
    相关资源
    最近更新 更多