变体宏不起作用

时间:2018-03-23 09:04:10

标签: c macros variadic-macros

我想要做的是使用宏访问代码。但编译器给了我这个错误

  

标识符“BUTTON___button”未定义

#define BUTTON_1                HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8)
#define BUTTON_2                HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_9)
#define BUTTON_3                HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)
#define BUTTON_4                HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5)
#define BUTTON_5                HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13)
#define BUTTON_6                HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_14)
#define BUTTON_7                HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_12)
#define BUTTON_8                HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_11)
#define BUTTON_9                HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15)
#define BUTTON_10               HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_0)
#define BUTTON_11               HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_10)
#define BUTTON_12               HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15)
#define BUTTON_13               HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1)
#define BUTTON_14               HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_2)
#define BUTTON_15               HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11)
#define BUTTON_16               HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2)
#define BUTTON_17               HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_0)
#define BUTTON_18               HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_1)
#define BUTTON_19               HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5)
#define BUTTON_20               HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_4)

#define BUTTON(...)             BUTTON_##__VA_ARGS__


for(uint8_t _button = 1; _button < 21; _button++)
    BUTTON(__button) //=> This should give me BUTTON(1) , BUTTON(2) ... each iteration.But not working

通过使用可变参数宏,我能得到我想要的吗?

3 个答案:

答案 0 :(得分:6)

您必须记住,预编译器事件是在编译代码之前发生的,并且是严格的纯文本替换。

因此,取决于由于运行时循环而具有不同值的变量是没有意义的,并且不起作用。

执行此操作的正确方法是将端口地址(GPIOA等)与每个端口的相应引脚一起放在一个数组中:

static const struct {
  const GPIO_TypeDef *port;
  uint32_t            pin;
} buttons[] = {
  { GPIOB, GPIO_PIN_8 },
  { GPIOB, GPIO_PIN_9 },
  ...
};

然后迭代数组中的数据:

for (size_t i = 0; i < sizeof buttons / sizeof *buttons; ++i)
{
  if (HAL_GPIO_ReadPin(buttons[i].port, buttons[i].pin))
  {
     ...
  }
}

答案 1 :(得分:3)

preprocessor在编译时工作,很早就参与进来(请阅读translation phases)。因此,您无法使用for循环生成宏。阅读documentation of cpp以及之后的C标准(例如n1570)。

您可以使用不同的程序生成C代码 - 可以是其他预处理器,如GPPm4,或某些脚本(或您自己的其他程序),以及自上个世纪以来,生成C文件是一种常见做法(例如,查看yaccrpcgen,但您会发现许多其他文件)。然后,您需要配置build automation工具(可能是makeninja)以适当地调用此类C代码生成器。

您可以获取预处理表单,例如如果使用GCC,则使用gcc -C -E。因此,您可以了解编译器(预处理后的翻译阶段)正在获取的内容。

  

通过使用可变参数宏,我能得到我想要的吗?

不,你不能。阅读documentation of variadic macros

答案 2 :(得分:1)

Variadic宏在这里没有解决任何问题。您有两个选项,查找表或X宏。查找表是首选,因为它们最具可读性。但是如果你需要最小化代码重复,X宏可能很有用,虽然它们有点难以阅读。

查找表版本:

typedef struct // I'm not sure about the exact types used here
{
  volatile uint8_t* port;
  uint8_t pin;
} button_t;

const button_t BUTTON[20] =
{
  {&GPIOB, 8},
  {&GPIOB, 9},
  ...
};


for(uint8_t i = 0; i<20; i++)
{
  HAL_GPIO_ReadPin(BUTTON[i].port, BUTTON[i].pin);
}

X宏版本:

#define BUTTON_LIST         \
  /*button  port  pin */    \
  X(1,      B,     8)       \
  X(2,      B,     9)       \
  X(3,      B,     4)       \
  X(4,      B,     5)       \
  X(5,      C,    13)

...

for(uint8_t button = 0; button<20; button++)
{
  #define X(button, port, pin) HAL_GPIO_ReadPin(GPIO##port, GPIO_PIN_##pin);
    BUTTON_LIST
  #undef X
}