宏定义中的数组

3

我想要实现类似这样的效果:

#define MACRO(x) {PORTB=0,PORTC=0,PORTD=0}

MACRO(0); //This would get replaced by PORTB=0;
MACRO(1); //PORTC=0;
MACRO(2); //PORTD=0;

我想创建一个“宏数组”。我将传递索引给它,它将返回正确的代码。
这可行吗?
编辑: 如果有帮助的话,PORTB、PORTC和PORTD都是#defines。
2个回答

5

可以使用预处理器进行操作,但这样做可能会被认为很丑陋。

#define MACRO_CASE0 PORTB = 0
#define MACRO_CASE1 PORTC = 0
#define MACRO_CASE2 PORTD = 0

#define MACRO(X) MACRO_CASE##X

此外,还要看一下Boost.Preprocessor库。(它适用于C和C++。)

更新:Jonathan Leffler的讨论之后(见下文),我感到有义务更新答案,并告诫新的C程序员不要滥用上面展示的(强大但肮脏的)技术。

如果你像OP请求的那样传递一个索引,它会返回正确的代码,那么你需要使用预处理器编程。然而,如果你只想根据某些条件执行不同的代码,并且如果该条件是编译时常量,则希望它没有运行时开销,则以下方法不仅更加简洁,而且更加灵活,因为它也允许传递运行时值。

/* '#include' this definition in any file where you want to use it. */
static inline void
do_the_right_thing(const int selector)
{
  switch (selector)
    {
   case 0:
      PORTB = 0;
      break;
   case 1:
      PORTC = 0;
      break;
   case 2:
      PORTD = 0;
      break;
   default:
      assert(!"cannot do the right thing: invalid selector");
    }
}

现在,在您的代码中,如果您编写以下代码:
do_the_right_thing(1);  /* selector is a compile-time constant */

一款启用适当优化的良好编译器与使用宏相比不会产生额外开销。但是,您也可以这样写:
do_the_right_thing(rand() % 3);  /* selector is a run-time expression */

编译器将插入一些快速切换的代码,以在运行时选择适当的操作。


与我的答案相比,这个方法的优点是它只能用于整数常量作为参数;缺点也在于此。 - Jonathan Leffler
@JonathanLeffler 确实,但是谁会想用除整数以外的任何东西来索引数组呢?如果你愿意,也可以使用符号名称。 - 5gon12eder
这取决于您是否希望动态选择索引:if (i >= 0 && i <= 2) MACRO(i); 或类似的东西。如果它是微控制器,我怀疑您不想要那样做,但我认为 MACRO(1); 比代码中的 PORTC=0; 更清晰 — 实际上,对我来说它不太清晰。但这在某种程度上可能是问题的产物。如果宏背后的代码选择了 PORTB、PORTC 或 PORTD 中的一个用于赋值语句的左侧(因此使用方式为 MACRO(1) = 0),那么我的建议将不起作用 — 正如我在“不扩展或概括”注释中所指出的那样。 - Jonathan Leffler
@JonathanLeffler 是的,我希望问题中的示例是虚构的,否则就是一个非常糟糕的想法。您对运行时表达式的看法是正确的。我没有考虑到它,因为我只在真正需要宏的时候才会使用宏。(也就是说,我想要分支编译,而不是控制流。)如果涉及控制流,则带有switch的内联函数将完美地完成任务,并且优化编译器将能够生成相同的代码,如果参数是编译时常量。 - 5gon12eder

3
这可以完成任务,但是无法很好地扩展或推广:
#define MACRO(x) (((x) == 0) ? PORTB=0 : ((x) == 1) ? PORTC=0 : PORTD=0)

...并且不太高效(原帖的代码看起来像是某些微控制器的代码)。 - Jabberwocky
@MichaelWalz:什么是低效的?对于问题中显示的示例,它是一个编译时常量。这本来就不是一个好主意,但它确实可以做到所需的功能。 - Jonathan Leffler
实际上它是高效的,因为编译器会对所有内容进行优化。宏MACRO(0)的预处理器输出为(((0) == 0) ? B=0 : ((0) == 1) ? C=0 : D=0) ; - Jabberwocky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接