C / C ++中的自展开宏循环

我目前正在开展一个项目,每个周期都很重要。 在分析我的应用程序时,我发现一些内部循环的开销非常高,因为它们只包含一些机器指令。 此外,这些循环中的迭代次数在编译时是已知的。

所以我认为不是手动展开带有复制和粘贴的循环,而是可以使用宏在编译时展开循环,以便以后可以轻松修改它。

我的形象是这样的:

#define LOOP_N_TIMES(N, CODE)  

这样我就可以替换for (int i = 0; i < N, ++i) { do_stuff(); } 用:

 #define INNER_LOOP_COUNT 4 LOOP_N_TIMES(INNER_LOOP_COUNT, do_stuff();) 

它将自己展开:

 do_stuff(); do_stuff(); do_stuff(); do_stuff(); 

由于C预处理器在大多数时间对我来说仍然是一个谜,我不知道如何实现这一点,但我知道它必须是可能的,因为Boost似乎有一个BOOST_PP_REPEAT宏。 不幸的是我不能在这个项目中使用Boost。

您可以使用模板进行展开。 请参阅拆卸样品Live on Godbolt

在此处输入图像描述

但是-funroll-loops对此示例具有相同的效果 。


住在科利鲁

 template  struct faux_unroll { template  static void call(F const& f) { f(); faux_unroll::call(f); } }; template <> struct faux_unroll<0u> { template  static void call(F const&) {} }; #include  #include  int main() { srand(time(0)); double r = 0; faux_unroll<10>::call([&] { r += 1.0/rand(); }); std::cout << r; } 

您可以使用预处理器并使用令牌连接和多个宏扩展来玩一些技巧,但您必须对所有可能性进行硬编码:

 #define M_REPEAT_1(X) X #define M_REPEAT_2(X) XX #define M_REPEAT_3(X) XXX #define M_REPEAT_4(X) XXXX #define M_REPEAT_5(X) X M_REPEAT_4(X) #define M_REPEAT_6(X) M_REPEAT_3(X) M_REPEAT_3(X) #define M_EXPAND(...) __VA_ARGS__ #define M_REPEAT__(N, X) M_EXPAND(M_REPEAT_ ## N)(X) #define M_REPEAT_(N, X) M_REPEAT__(N, X) #define M_REPEAT(N, X) M_REPEAT_(M_EXPAND(N), X) 

然后像这样展开它:

 #define THREE 3 M_REPEAT(THREE, three();) M_REPEAT(4, four();) M_REPEAT(5, five();) M_REPEAT(6, six();) 

这个方法需要字面数作为计数,你不能做这样的事情:

 #define COUNT (N + 1) M_REPEAT(COUNT, stuff();) 

没有标准的方法可以做到这一点。

这是一个有点疯狂的方法:

 #define DO_THING printf("Shake it, Baby\n") #define DO_THING_2 DO_THING; DO_THING #define DO_THING_4 DO_THING_2; DO_THING_2 #define DO_THING_8 DO_THING_4; DO_THING_4 #define DO_THING_16 DO_THING_8; DO_THING_8 //And so on. Max loop size increases exponentially. But so does code size if you use them. void do_thing_25_times(void){ //Binary for 25 is 11001 DO_THING_16;//ONE DO_THING_8;//ONE //ZERO //ZERO DO_THING;//ONE } 

要求优化器消除死代码并不是太多。 在这种情况下:

 #define DO_THING_N(N) if(((N)&1)!=0){DO_THING;}\ if(((N)&2)!=0){DO_THING_2;}\ if(((N)&4)!=0){DO_THING_4;}\ if(((N)&8)!=0){DO_THING_8;}\ if(((N)&16)!=0){DO_THING_16;} 

您不能使用#define构造来计算“unroll-count”。 但是如果有足够的宏,你可以定义:

 #define LOOP1(a) a #define LOOP2(a) a LOOP1(a) #define LOOP3(a) a LOOP2(a) #define LOOPN(n,a) LOOP##n(a) int main(void) { LOOPN(3,printf("hello,world");); } 

用VC2012测试

你不能用宏编写真正的递归语句,我很确定你也不能在宏中进行真正的迭代。

但是你可以看一下Order 。 虽然它完全构建在C预处理器之上,但它“实现”类似迭代的function。 它实际上可以有多达N次迭代,其中N是一些大数。 我猜它与“递归”宏类似。 无论如何,这是一个很少有编译器支持它的边缘情况(GCC就是其中之一)。