在没有循环的情况下重复完全相同的代码段 1000 次
Repeating an exact same code segment 1000 times without loop
出于某种原因(与性能测量相关),我需要将一个代码段重复 1000 次(1024 次也可以),但没有 "for" 或任何其他循环。
显然,我很可能会编写一个如下所示的宏:
#define RUN_1000_TIMES(x) \
x \
x \
x \
...
... /* (999+1 times the same line) */
...
x \
x
...然后将该宏应用到我的代码段。
但是有没有比 1000 行长的宏更优雅的解决方案呢?
#define RUN_1024_TIMES(x) do {RUN_512_TIMES(x); RUN_512_TIMES(x); } while(0)
#define RUN_512_TIMES(x) do {RUN_256_TIMES(x); RUN_256_TIMES(x); } while(0)
#define RUN_256_TIMES(x) do {RUN_128_TIMES(x); RUN_128_TIMES(x); } while(0)
#define RUN_128_TIMES(x) do {RUN_64_TIMES(x); RUN_64_TIMES(x); } while(0)
#define RUN_64_TIMES(x) do {RUN_32_TIMES(x); RUN_32_TIMES(x); } while(0)
#define RUN_32_TIMES(x) do {RUN_16_TIMES(x); RUN_16_TIMES(x); } while(0)
#define RUN_16_TIMES(x) do {RUN_8_TIMES(x); RUN_8_TIMES(x); } while(0)
#define RUN_8_TIMES(x) do {RUN_4_TIMES(x); RUN_4_TIMES(x); } while(0)
#define RUN_4_TIMES(x) do {RUN_2_TIMES(x); RUN_2_TIMES(x); } while(0)
#define RUN_2_TIMES(x) do {x; x; } while(0)
do{ ... } while(0)
仅适用于您用if (....) RUN_1024_TIMES(...);
调用它的情况。不需要的时候可以去掉。
你也可以每个宏执行 3 次:
#define RUN_1000_TIMES(x) do {RUN_729_TIMES(x); RUN_243_TIMES(x); RUN_27_TIMES(x); x; } while(0)
#define RUN_729_TIMES(x) do {RUN_243_TIMES(x); RUN_243_TIMES(x); RUN_243_TIMES(x); } while(0)
#define RUN_243_TIMES(x) do {RUN_81_TIMES(x); RUN_81_TIMES(x); RUN_81_TIMES(x); } while(0)
#define RUN_81_TIMES(x) do {RUN_27_TIMES(x); RUN_27_TIMES(x); RUN_27_TIMES(x); } while(0)
#define RUN_27_TIMES(x) do {RUN_9_TIMES(x); RUN_9_TIMES(x); RUN_9_TIMES(x); } while(0)
#define RUN_9_TIMES(x) do {RUN_3_TIMES(x); RUN_3_TIMES(x); RUN_3_TIMES(x); } while(0)
#define RUN_3_TIMES(x) do {x; x; x; } while(0)
在 Python 文件中,输入:
print("//header of the code")
for i in range(1000):
print("x;")
print("//bottom of the code")
然后:
./gen.py > file.c
这将比您使用 C 预处理器所做的更简单,它不能执行循环之类的事情!
#define RUN_10_TIMES(X) X X X X X X X X X X
#define RUN_1000_TIMES(X) RUN_10_TIMES(RUN_10_TIMES(RUN_10_TIMES(X)))
请注意,您可以在 "invocation" 中递归地 "call" 一个类似语法的宏(因此 FOO(FOO(FOO(X)))
没问题);这是因为类函数宏调用的第一步使用了参数替换,它对递归没有限制。参数替换具体涉及评估其相应参数出现在替换列表中(并且未被字符串化或作为粘贴的一部分)的任何参数,就好像它自己在一行上一样,然后使用生成的扩展来替换每个此类参数。在参数替换(和 paste/stringifications)之后,生成的替换列表在 重新扫描和进一步替换 步骤中重新扫描;在 this 步骤中,宏被标记为 "blue paint" (意思是,其他调用将被忽略)。类似调用的递归完全是参数替换的函数,所以它是允许的。
您可以正常编写循环,然后只需告诉编译器您希望展开循环。写得很好,和你写的 1000 行一样完美。
执行此操作的方法取决于您的编译器。我会写GCC的答案,这是我常用的编译器,但其他编译器应该类似。
如果您想展开代码中的所有循环,则更容易:只需在命令行中添加一两个选项即可:
-funroll-loops
-funroll-all-loops
如果您想了解更多关于这些选项的行为,请参阅编译器手册。 SO 上也有关于它们的问题。
如果你只想展开一个特定的循环,而保留所有其他循环,则比较困难,但也可以做到。检查这个 SO 答案:
"sad" 部分可能是一个足够聪明的编译器...让它成为一个循环!
出于某种原因(与性能测量相关),我需要将一个代码段重复 1000 次(1024 次也可以),但没有 "for" 或任何其他循环。
显然,我很可能会编写一个如下所示的宏:
#define RUN_1000_TIMES(x) \
x \
x \
x \
...
... /* (999+1 times the same line) */
...
x \
x
...然后将该宏应用到我的代码段。
但是有没有比 1000 行长的宏更优雅的解决方案呢?
#define RUN_1024_TIMES(x) do {RUN_512_TIMES(x); RUN_512_TIMES(x); } while(0)
#define RUN_512_TIMES(x) do {RUN_256_TIMES(x); RUN_256_TIMES(x); } while(0)
#define RUN_256_TIMES(x) do {RUN_128_TIMES(x); RUN_128_TIMES(x); } while(0)
#define RUN_128_TIMES(x) do {RUN_64_TIMES(x); RUN_64_TIMES(x); } while(0)
#define RUN_64_TIMES(x) do {RUN_32_TIMES(x); RUN_32_TIMES(x); } while(0)
#define RUN_32_TIMES(x) do {RUN_16_TIMES(x); RUN_16_TIMES(x); } while(0)
#define RUN_16_TIMES(x) do {RUN_8_TIMES(x); RUN_8_TIMES(x); } while(0)
#define RUN_8_TIMES(x) do {RUN_4_TIMES(x); RUN_4_TIMES(x); } while(0)
#define RUN_4_TIMES(x) do {RUN_2_TIMES(x); RUN_2_TIMES(x); } while(0)
#define RUN_2_TIMES(x) do {x; x; } while(0)
do{ ... } while(0)
仅适用于您用if (....) RUN_1024_TIMES(...);
调用它的情况。不需要的时候可以去掉。
你也可以每个宏执行 3 次:
#define RUN_1000_TIMES(x) do {RUN_729_TIMES(x); RUN_243_TIMES(x); RUN_27_TIMES(x); x; } while(0)
#define RUN_729_TIMES(x) do {RUN_243_TIMES(x); RUN_243_TIMES(x); RUN_243_TIMES(x); } while(0)
#define RUN_243_TIMES(x) do {RUN_81_TIMES(x); RUN_81_TIMES(x); RUN_81_TIMES(x); } while(0)
#define RUN_81_TIMES(x) do {RUN_27_TIMES(x); RUN_27_TIMES(x); RUN_27_TIMES(x); } while(0)
#define RUN_27_TIMES(x) do {RUN_9_TIMES(x); RUN_9_TIMES(x); RUN_9_TIMES(x); } while(0)
#define RUN_9_TIMES(x) do {RUN_3_TIMES(x); RUN_3_TIMES(x); RUN_3_TIMES(x); } while(0)
#define RUN_3_TIMES(x) do {x; x; x; } while(0)
在 Python 文件中,输入:
print("//header of the code")
for i in range(1000):
print("x;")
print("//bottom of the code")
然后:
./gen.py > file.c
这将比您使用 C 预处理器所做的更简单,它不能执行循环之类的事情!
#define RUN_10_TIMES(X) X X X X X X X X X X
#define RUN_1000_TIMES(X) RUN_10_TIMES(RUN_10_TIMES(RUN_10_TIMES(X)))
请注意,您可以在 "invocation" 中递归地 "call" 一个类似语法的宏(因此 FOO(FOO(FOO(X)))
没问题);这是因为类函数宏调用的第一步使用了参数替换,它对递归没有限制。参数替换具体涉及评估其相应参数出现在替换列表中(并且未被字符串化或作为粘贴的一部分)的任何参数,就好像它自己在一行上一样,然后使用生成的扩展来替换每个此类参数。在参数替换(和 paste/stringifications)之后,生成的替换列表在 重新扫描和进一步替换 步骤中重新扫描;在 this 步骤中,宏被标记为 "blue paint" (意思是,其他调用将被忽略)。类似调用的递归完全是参数替换的函数,所以它是允许的。
您可以正常编写循环,然后只需告诉编译器您希望展开循环。写得很好,和你写的 1000 行一样完美。
执行此操作的方法取决于您的编译器。我会写GCC的答案,这是我常用的编译器,但其他编译器应该类似。
如果您想展开代码中的所有循环,则更容易:只需在命令行中添加一两个选项即可:
-funroll-loops
-funroll-all-loops
如果您想了解更多关于这些选项的行为,请参阅编译器手册。 SO 上也有关于它们的问题。
如果你只想展开一个特定的循环,而保留所有其他循环,则比较困难,但也可以做到。检查这个 SO 答案:
"sad" 部分可能是一个足够聪明的编译器...让它成为一个循环!