【问题标题】:C/C++ macro to repeat code重复代码的 C/C++ 宏
【发布时间】:2015-01-15 00:08:23
【问题描述】:

有没有办法用宏重复一个 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”有一个宏。这样我也可以简单地更改 N 来修改程序而无需重写它。

提前谢谢你

【问题讨论】:

  • 计算出设置循环所需的时间,以及进行一次迭代所需的时间...如果所需时间大于总和,则根据需要进行设置加上尽可能多的迭代几乎达到您的总数,然后只需几个nops 即可完成延迟。编写起来更费力,但更紧凑。
  • ..如果延迟不是那么长,请尝试使用 5 nops 的宏来节省输入,但我认为没有办法制作“粘贴此 N 次" 你所要求的宏。
  • 您可以创建 n 个宏,其中 n 是您可能需要的最大重复次数。像#define _5(x) x ## _4(x) 这样的东西,_1(x) ... _4(x) 看起来很相似
  • 许多汇编语言都有用于重复代码块的宏。您可能想在汇编代码中编写延迟。
  • 看看stackoverflow.com/questions/319328/… 使用宏生成循环

标签: c++ c macros arduino metaprogramming


【解决方案1】:

根据 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

【讨论】:

    【解决方案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.
    

    【讨论】:

      【解决方案3】:

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

      //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 无
      10c: 00 00 无
      10e: 00 00 无
      110: 00 00 无
      112: 00 00 无
      114: 00 00 无
      116: 00 00 无
      118: 00 00 无
      11a: 00 00 无
      11c: 00 00 无
      11e: 08 95 回复

      我在 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 用于 C++ 非预处理器解决方案。这正是在编译时使用模板编程展开循环非常有用的边缘情况之一。
      【解决方案4】:

      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);
      

      【讨论】:

        猜你喜欢
        • 2011-03-10
        • 1970-01-01
        • 2011-01-24
        • 2011-04-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-20
        • 2012-01-21
        相关资源
        最近更新 更多