C-Macros会产生意外行为

时间:2014-03-16 17:06:04

标签: c macros c-preprocessor precompile pre-compilation

我正在尝试使用宏轻松更改我的头文件。我正在调试我的代码,似乎这些MACROS没有做他们应该做的事情。谁能告诉我如何实现以下效果? LED_ID_AMS等。

#define LED_NUMBER                  (2)
#define LED_ID_X                    (0)
#define LED_ID_Y                    (1)
#define LED_PIN_X                   (0)
#define LED_PIN_Y                   (3)
#define LED_PORT_X                  (PORTE)
#define LED_PORT_Y                  (PORTG)
#define LED_DD_X                    (DDRE)
#define LED_DD_Y                    (DDRG)
#define LED_PORT(LED_ID_X)          (LED_PORT_X)
#define LED_PORT(LED_ID_Y)          (LED_PORT_Y)
#define LED_PIN(LED_ID_X)           (LED_PIN_X)
#define LED_PIN(LED_ID_Y)           (LED_PIN_Y)
#define LED_DD(LED_ID_X)            (LED_DD_X)
#define LED_DD(LED_ID_Y)            (LED_DD_Y)

我想要实现的目标是什么?

我正在尝试这样做,所以我可以像这样循环端口init:

for(i=0;i<LED_NUMBER;i++){
    /* set data direction to output*/
    LED_DD(i)|=((0x01)<<LED_PIN(i));
    /* turn on led */
    LED_PORT(i)|=((0x01)<<LED_PIN(i));
}

3 个答案:

答案 0 :(得分:1)

您将后悔使用过多的宏。实际上,你已经后悔了,因为它们不起作用,并且作为宏,它们很难调试。

只需几点:

  • 您的LED_PIN(i)表达式始终扩展为0
  • 您的LED_PORT(i)表达式始终会扩展为PORTE

例如LED_PIN(LED_ID_X)扩展为LED_PIN_X。注意,根本不使用宏参数LED_ID_X。相反,LED_PIN_X只会扩展为0

答案 1 :(得分:0)

您必须至少添加以下内容之一:

  • 阵列
  • 内联函数
  • 更复杂的宏

在我看来,还需要取消引用硬件地址。

例如,使用宏,您可以定义:

#define LED_PORT(i) *(uint16_t *)( \
    (i) == LED_ID_X ? LED_PORT_X : \
    (i) == LED_ID_Y ? LED_PORT_Y : \
    etc)

其中:

#define LED_ID_X     (0)
#define LED_ID_Y     (1)
#define LED_PORT_X   (PORTE)
#define LED_PORT_Y   (PORTG)
#define PORTE        (0x11112222U) // example only
#define PORTG        (0x33334444U) // example only

这里uint16_t只是猜测:我假设32位地址空间中有16位端口。

或者,使用数组和C99指定的初始值设定项:

const uint32_t LED_PORT[] = {
    [LED_ID_X] = LED_PORT_X,
    [LED_ID_Y] = LED_PORT_Y
};

#define LED_PORT(i) (*(uint16_t *)LED_PORT[i])

当然,如果没有C99,你可以使用:

const uint32_t LED_PORT[] = {LED_PORT_X, LED_PORT_Y};

其中假定 LED_ID_X0等。

答案 2 :(得分:0)

这应该尖叫警告你,例如LED_PORT(SOME_ARG)有几个定义。在LED_PORT(LED_ID_X)中,LED_ID_X只是一个虚拟参数,与你的常量LED_ID_X完全无关。

您可以使用常量数组使您的代码具有相同的可读性,也可以像您在此处尝试的那样使用宏。

除非大量LED_ID_<foo>,否则这只是一个小小的简化。不要那样做。如果有大量的代码与它们大致相同,那么定义一个迭代每个代码的宏可能是有意义的,即:

#define FROB_LEDS \\
     action(LED_ID_X); \\
     action(LED_ID_Y); \\
     action(LED_ID_Z);

并在本地将action(X)定义为宏,以便对LED XFROBaction再次执行操作。非常丑陋,真实。