【问题标题】:Repeating an exact same code segment 1000 times without loop在没有循环的情况下重复完全相同的代码段 1000 次
【发布时间】:2019-04-30 16:34:30
【问题描述】:

出于某种原因(与性能测量有关),我需要重复一个代码段 1000 次(1024 次也可以),但没有“for”或任何其他循环。

显然,我很可能会编写一个如下所示的宏:

#define RUN_1000_TIMES(x)   \
x                           \
x                           \
x                           \
...
...  /* (999+1 times the same line) */
...
x                           \
x

...然后将该宏应用于我的代码段。

但是还有比 1000 行长的宏更优雅的解决方案吗?

【问题讨论】:

  • 你可以把它写在一个循环中并强制编译器展开循环。
  • @CacahueteFrito 这将是一个合理的答案 - 但是,你是怎么做到的?
  • @CacahueteFrito 我怀疑你能否说服理智的编译器展开 1000 次迭代的循环。
  • @EugeneSh。看我的回答。我不认为编译器可以选择不服从,但我不确定。

标签: c c-preprocessor preprocessor


【解决方案1】:
#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)

【讨论】:

  • .. 或者您可以在其他每个宏中使用RUN_2_TIMES
  • do..while 块的唯一问题是代码可能需要一个公共范围。
  • @EugeneSh。是的,取决于x 是什么。
【解决方案2】:

在 Python 文件中,输入:

print("//header of the code")
for i in range(1000):
    print("x;")
print("//bottom of the code")

然后:

./gen.py > file.c

这将比你可以用 C 预处理器做的任何事情都更简单,因为它不能执行像循环这样的事情!

【讨论】:

  • 你也可以在 C 中做到这一点 :)
【解决方案3】:
#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)))

请注意,您可以在类似语法的“调用”中递归地“调用”宏(所以FOO(FOO(FOO(X))) 可以);这是因为类函数宏调用的第一步使用了参数替换,它对递归没有限制。参数替换具体涉及评估其对应参数出现在替换列表中(并且不是字符串化或粘贴的一部分)的任何参数,就好像它本身在一行上,然后使用生成的扩展替换每个这样的参数。在参数替换(和粘贴/字符串化)之后,在重新扫描和进一步替换步骤中重新扫描生成的替换列表;在 this 步骤中,宏被标记为“蓝色油漆”(意思是,其他调用被忽略)。类调用递归完全是一个参数替换的函数,所以它是允许的。

【讨论】:

    【解决方案4】:

    您可以正常编写循环,然后告诉编译器您希望展开循环。它写得很好,就像你写了 1000 行一样最佳。

    执行此操作的方式取决于您的编译器。我会写GCC的答案,这是我通常使用的编译器,但其他编译器应该是类似的。

    如果您想展开代码中的所有循环,则更简单:您只需在命令行中添加一个或两个选项:

    -funroll-loops
    -funroll-all-loops
    

    如果您想了解更多关于这些选项的行为,请参阅编译器手册。在 SO 上也有关于它们的问题。

    如果您只想展开特定循环,并保留所有其他循环,则比较困难,但也可以做到。检查这个 SO 答案:https://stackoverflow.com/a/14251545/6872717

    【讨论】:

      【解决方案5】:

      您可以为此使用 P99:http://p99.gforge.inria.fr/p99-html/group__preprocessor__for_gaec0c87b336a5fa2a8230e207af5cc1f0.html#gaec0c87b336a5fa2a8230e207af5cc1f0

      “可悲”的部分是它可能是一个足够聪明的编译器......让它成为一个循环!

      【讨论】:

        猜你喜欢
        • 2015-10-12
        • 2022-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多