C / C ++宏重复代码

时间:2014-11-17 22:57:39

标签: c++ c macros arduino metaprogramming

有没有办法用宏重复C代码N次? N也是一个宏 例如,如果我有这个宏:

#define N 5  
#define COODE "nop\n\t"
#define REPEAT [...]

当我调用repeat时,预处理器会将CODE写入N次,所以

 __asm__(REPEAT);

会变成

__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");

我有一个Arduino必须等待一个精确(和小,约10-15)的时钟数。每个" nop" (无操作)需要1个时钟周期才能执行,它什么都不做。我不能只做一个循环,因为每个循环都在多个操作中执行(初始化计数器,递增计数器,检查是否到达结束),所以不要手动编写" nop \ n \ t& #34;我想要一个宏。这样我也可以简单地改变N来修改程序而不重写它。

提前谢谢

4 个答案:

答案 0 :(得分:6)

如果您想在不包含整个库或使用define的情况下执行此操作,则可以使用简单递归模板:

//By Christopher Andrews, released under MIT licence.

template< unsigned N > struct Nops{
  static void generate() __attribute__((always_inline)){
    __asm__ volatile ("nop");
    Nops< N - 1 >::generate();
  }
};
template<> struct Nops<0>{ static inline void generate(){} };

void setup() {
  Nops<10>::generate();
}

void loop(){}

这将生成所需的确切数量的nop。

  

0000010a设置:
   10a:00 00 nop
   10c:00 00 nop
   10e:00 00 nop
   110:00 00 nop
   112:00 00 nop
   114:00 00 nop
   116:00 00 nop
   118:00 00 nop
   11a:00 00 nop
   11c:00 00 nop
   11e:08 95 ret

我在Arduino的TFT驱动程序中使用过这种方法。

编辑:

还有另一种方法可以在使用avr-gcc编译的AVR上轻松完成此操作。我假设这可能不适用于较旧的工具链。

  

为了延迟执行特定数量的周期,GCC   工具

     

void __builtin_avr_delay_cycles (unsigned long ticks) ticks是延迟执行的滴答数。请注意,这个内置功能   不考虑可能增加的中断的影响   延迟时间。 ticks必须是编译时整数常量;延误   不支持可变数量的周期

从这里开始:https://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/AVR-Built_002din-Functions.html

答案 1 :(得分:2)

以下代码适用于GNU C,

#define NOP __asm__("nop")

#define ten(a)     a;a;a;a;a;a;a;a;a;a
#define handred(a) ten(ten(a))


int
main()
{
    handred(NOP);
    return 0;
}

编译和调试:

code@lab:~/debug$ gcc -g -o debug_NOP debug_NOP.c
code@lab:~/debug$ gdb -q --nh debug_NOP
Reading symbols from debug_NOP...done.
(gdb) set disassembly-flavor intel
(gdb) start
Temporary breakpoint 1 at 0x664: file debug_NOP.c, line 10.
Starting program: /home/code/debug/debug_NOP 

Temporary breakpoint 1, main () at debug_NOP.c:10
10      handred(NOP);
(gdb) disassemble 
Dump of assembler code for function main:
   0x0000555555554660 <+0>: push   rbp
   0x0000555555554661 <+1>: mov    rbp,rsp
=> 0x0000555555554664 <+4>: nop
   0x0000555555554665 <+5>: nop
   0x0000555555554666 <+6>: nop
   0x0000555555554667 <+7>: nop
   0x0000555555554668 <+8>: nop
   0x0000555555554669 <+9>: nop
   ....
   0x00005555555546c6 <+102>:   nop
   0x00005555555546c7 <+103>:   nop
   0x00005555555546c8 <+104>:   mov    eax,0x0
   0x00005555555546cd <+109>:   pop    rbp
   0x00005555555546ce <+110>:   ret    
End of assembler dump.

答案 2 :(得分:0)

Boost有Boost.Preprocessor,除此之外还有其他功能。从:

http://www.boost.org/doc/libs/1_57_0/libs/preprocessor/doc/index.html

<强> BOOST_PP_REPEAT

代码:

#include <boost/preprocessor/repetition/repeat.hpp>

#define OP(z, n, text) text
...
__asm__( BOOST_PP_REPEAT(5, OP, "noop\n"\t);

答案 3 :(得分:0)

根据Chris A的回答,这是一种更简单的方法,似乎也对我有用:

template< unsigned N > 
inline static void nops(){
    asm ("nop");
    nops< N - 1 >();
}

template<> inline void nops<0>(){};

void setup() {
  nops<10>();
}

https://godbolt.org/z/a7MMea