C宏向导,用于将语句乘以N次

时间:2013-12-05 09:37:27

标签: c macros embedded

我有以下宏来接受一个陈述并将其相乘

#define X2(s)  do { s; s; } while (0)
#define X3(s)  do { s; s; s; } while (0)
#define X4(s)  do { s; s; s; s; } while (0)
#define X5(s)  do { s; s; s; s; s; } while (0)
#define X6(s)  do { s; s; s; s; s; s; } while (0)
etc.

所以预处理器扩展

X2(i++)

do { i++; i++; } while (0)

我想要一个宏

#define CODE_MULTIPLIER(x,s) 

扩展声明sx次。所以

CODE_MULTIPLIER(3,j--)

将扩展为

do { j--; j--; j--; } while (0)

我提出的丑陋想法是:

#define CODE_MULTIPLIER(x,s) do {       \
       if ((x) == 1) { s; }             \
  else if ((x) == 2) { s; s; }          \
  else if ((x) == 3) { s; s; s; }       \
  else if ((x) == 4) { s; s; s; s; }    \
  else if ((x) == 5) { s; s; s; s; s; } \
  etc.                                  \
  else assert(0);                       \
  } while (0)

希望编译器能够优化if s

为什么你会想要这样的宏? 一个原因(但不是唯一的原因)是嵌入式编程中需要精确延迟。使用while / for循环稍微改变时间。循环的编译器优化可能无法保留精密的时序要求。

以下是一个典型的用法示例:

#define CLOCK_FREQ_Hz      (16000000L)
#define US_TO_NOPS(us)     ((us) * CLOCK_FREQ_Hz / 1000000L)

#define OFF_ON_DELAY_US    (4) // units: microseconds
#define ON_OFF_DELAY_US    (2) // units: microseconds

#define OFF_ON_DELAY_NOPS US_TO_NOPS(OFF_ON_DELAY_US) // units: instructions
#define ON_OFF_DELAY_NOPS US_TO_NOPS(ON_OFF_DELAY_US) // units: instructions

PIN = OFF;
CODE_MULTIPLIER(OFF_ON_DELAY_NOPS,asm("nop")); // 4us delay
PIN = ON;
CODE_MULTIPLIER(ON_OFF_DELAY_NOPS,asm("nop")); // 2us delay
PIN = OFF; 

我很感激有关如何创建此宏的任何建议。高度偏好独立于编译器的宏巫术(我们的嵌入式家伙并不总是有使用GCC的奢侈品)

感谢名单

2 个答案:

答案 0 :(得分:1)

是的,如果你不做太多的事情,这样的事情是可能的。 P99有一整套宏来完成不同类型的这种展开。这里很容易就是

#define toto(I) f(I)

P99_UNROLL(toto, 3);  // => f(0); f(1); f(2);

但请注意,对于使用P99,您需要一个能够实现符合C99标准的预处理器的编译器。

答案 1 :(得分:1)

由于递归通常不能在宏中使用,并且您可能没有“扩展展开功能”,因此获得“始终有效的解决方案”的唯一方法是执行一些手动操作,如下所示:

#define X1(s)  do { s;} while (0)
#define X2(s)  do { s; s; } while (0)
#define X3(s)  do { s; s; s; } while (0)
#define X4(s)  do { s; s; s; s; } while (0)
#define X5(s)  do { s; s; s; s; s; } while (0)
#define X6(s)  do { s; s; s; s; s; s; } while (0)
#define CODE_MULTIPLIER(s, i) X##i(s)

您只需在代码中使用CODE_MULTIPLIER(s, i)即可。这样就可以避免使用if / else if条件表达式。例如,您将使用CODE_MULTIPLIER(i++,3)。 如果你不打算使用X1,X2 ......可以应用另一个技巧....但只有CODE_MULTIPLIER(s,i):

#define X1(s)  s
#define X2(s)  s; X1(s)
#define X3(s)  s; X2(s)
#define X4(s)  s; X3(s)
#define X5(s)  s; X4(s)
#define X6(s)  s; X5(s)
#define CODE_MULTIPLIER(s, i) do { X##i(s); } while (0)

有一个更好的sintax。