使用具有goto和标签的宏展开循环

时间:2015-03-16 14:40:02

标签: c++ c compiler-errors

此问题与C或C ++语言功能严格相关。我不建议将下面的代码作为设计模式。我不使用它,我不鼓励它。但我只是想提高自己的知识!

我有一个包含标签和转到条件的定义。

#define BROP(num, sum)                  \
num = rand_lcg(generated);              \
if (num % 2)                            \
{                                       \
rng1:                                   \
    generated = rand_lcg(generated);    \
    if (generated < 512)                \
        sum -= generated;               \
    else                                \
        goto rng1;                      \
}

稍后在代码中我使用它:

for (i = 0; i < iterations; i++)
{
    BROP(num, sum);
    BROP(num, sum);
    BROP(num, sum);
    // ...
}

我最终处于循环展开并且标签重新定义的情况。

我是否可以使用智能构造使编译器在每次定义“实例化”时重命名标签?

我知道避免这种说法的所有选择,但我仍然不知道问题的答案。

2 个答案:

答案 0 :(得分:3)

你真的应该让它成为do ... while循环:

#define BROP(num, sum)  do{                \
   bool again = false;                     \
   num = rand_lcg(generated);              \
   if (num % 2)  {                         \
   do { again = false;                     \
     generated = rand_lcg(generated);      \
     if (generated < 512)                  \
           sum -= generated;               \
     else                                  \
        again = true;                      \
   } while(again); } while(0)

有关旧外do{ ... }while(0)技巧,请参阅this

如果您(错误地)坚持使用标签并使用GCC编译器(或Clang/LLVM应该与之兼容),您可以使用local labels扩展名(即__label__ ...)

您也可以使用预处理器中的concatenation__LINE__号码生成标签。从

中获取灵感
#define STUPID_LOOP_BIS(Test,Lin) do { \
 lab##Lin: if (Test) goto lab##Lin; } while(0)
#define STUPID_LOOP_AT(Test,Lin) STUPID_LOOP_BIS(Test,Lin)
#define STUPID_LOOP(Test) STUPID_LOOP_AT(Test,__LINE__)

由于不明原因,您需要所有三个宏!

并使用

  STUPID_LOOP(x++ < 100);
  STUPID_LOOP(y-- > 0);

在不同的行上。当然,根据您的需要进行调整和改进。

你绝对应该使用信任更多的编译器优化能力并拥有static inline个功能。并非每个测试都编译到机器分支(例如,因为CMOV instructions);并非每个循环都被编译为机器循环(例如,因为loop unrolling)。您可能正在失去开发人员的时间,更重要的是,您通过技巧禁用优化(因此您的代码可能会变慢,而不是更快)。

如果使用GCC或Clang启用优化和警告:所以使用gcc -Wall -Wextra -O3 -mtune=native进行编译

答案 1 :(得分:2)

忽略它的原因,以下版本的BROP完全编译为C和C ++

#define BROP(num, sum, lbl)            \
num = rand_lcg(generated);              \
if (num % 2)                            \
{                                       \
lbl :                                   \
    generated = rand_lcg(generated);    \
    if (generated < 512)                \
        sum -= generated;               \
    else                                \
        goto lbl;                      \
}

我将其作为

调用
for (i = 0; i < 1000; i++)
{
    BROP(num,sum, lbl1);
    BROP(num,sum, lbl2);
}

这不依赖于任何编译器扩展,因此您应该能够在大量编译器中使用它。