【问题标题】:Rewriting for loop efficiently, C高效地重写 for 循环,C
【发布时间】:2011-06-26 16:31:11
【问题描述】:

我想使用一个字节变量i 来执行一段代码 256 次。下面的行无限循环,是否有一个整洁的替代方案可以工作?

for (i = 0; i < 255; i++){

希望不使用:

  • 16 位变量,(或任何额外的位)
  • 嵌套循环
  • while(1)
  • break; 声明

谢谢

【问题讨论】:

  • 为什么它会无限循环?
  • 因为i 永远不会达到 256,因为它是一个 8 位无符号数
  • @Armen 达到 255 并切换回 0
  • @Jodes: 是i 是无符号的8bit,它的最大值是255。上面不会无限循环。 (但它只会循环 255 次)。
  • @Jodes:如果您因为使用不寻常的平台而有不寻常的要求,我建议您在问题中提请注意。如果从一开始就很清楚您正在为 8 位微控制器构建(我完全相信您可能会变得更小/更快使用 8 位类型的代码)...

标签: c for-loop infinite-loop


【解决方案1】:
i = 0;
do {
  f(i);
} while(i++!=255);

【讨论】:

    【解决方案2】:

    总是可以这样做:

    for (i = 0; i != 255; ++i)
    {
        f(i);
    }
    f(255);
    

    老实说,您最好只使用int。如果您使用 8 位整数,它不会更快。无论如何,它都会在寄存器中。

    【讨论】:

    • +1。如果你真的想这样做并且必须避免索引更大的数据类型。
    • 如果目标机器有 4 位处理器怎么办?
    • C 语言要求int 的范围至少为 16 位。
    • @WTP 如果目标机器是算盘怎么办?
    • @WTP 算盘计算机图灵完备。
    【解决方案3】:
    uint8_t i = 0;
    do {
        ...
    } while ((++i) != 0);
    

    当然假设i 会溢出。这不是 C 标准所保证的,但几乎总是在编译器没有进行过多优化时发生。

    【讨论】:

    • 不错的解决方案!比我的好多了:/ +1
    • 标准对无符号类型的算术进行了很好的定义:它可以工作modulus (MAX_FOR_TYPE + 1)。您的解决方案按原样运行。
    • @pmg,哈,是的,我现在检查了。我认为这个限制适用于无符号和有符号的数学。感谢您的评论!
    【解决方案4】:

    我想说展开循环是最明显的方法:

    uint8_t i = 0;
    for ( i = 0; i < 32; i++ )
    {
        printf("Instance of loop %d\n", (8*i)+0);
        printf("Instance of loop %d\n", (8*i)+1);
        printf("Instance of loop %d\n", (8*i)+2);
        printf("Instance of loop %d\n", (8*i)+3);
        printf("Instance of loop %d\n", (8*i)+4);
        printf("Instance of loop %d\n", (8*i)+5);
        printf("Instance of loop %d\n", (8*i)+6);
        printf("Instance of loop %d\n", (8*i)+7);
    }
    

    理论上,这也应该更快,因为您的测试和跳转次数更少。如果需要,您也可以比这更严格地展开。

    您可能还对Duff's device (SO question explaining it) 感兴趣,它可以让您展开任何大小的循环,而不仅仅是具有良好因素的循环。当然有限制,因为它要求你在内存中存储你需要的数量,在这种情况下超过 8 位字段,但是,为了循环,比如 137 次,它会派上用场。

    请注意,您不需要执行 8*i+1 阶段,这只是为了验证是否发生了足够多的事件。

    另一个注释:“但我不想将我的代码写 8 次!”可以根据需要使用 inline 函数 (C99) 或宏 (C89) 来克服。

    【讨论】:

    • 由于 OP 似乎关心微优化,您可以将循环更改为 += 8 并避免 8 次乘法。
    • @Chris += 8 的问题是最后一次迭代落在 256 上,你不能用 uint8_t 表示。您必须开始使用两个变量(一个用于计数,一个增加 8 以避免乘法)——这取决于该阶段哪个成本最高。我稍微假设 OP 实际上不需要知道循环号,而只需执行代码 256 次。
    【解决方案5】:

    如果“byte”是char,在 char 被签名(和 8 位)的系统上它总是 unsigned char,它应该适用于您的循环。

    如果不只是实验,请改用int

    【讨论】:

      【解决方案6】:

      我能想到的唯一方法是使用布尔值

      b = 1;
      for(i = 0; i != 0 || b; i++)
      {
          b = 0;
          ...
      }
      

      或者您可以使用一个短字节来代替,它是一个字节大小的 2 倍。

      发生的情况是最大无符号字节值为 255。我不确定无符号字节会发生什么,但是当您溢出时,有符号字节变为负数。

      【讨论】:

        【解决方案7】:

        i 声明为int 通常最快。我无法想象为什么要使用 8 位整数循环。也许你认为它会比int 更快,但它不会。

        【讨论】:

          【解决方案8】:

          编辑:我弄错了,它循环了 255 次... :) do-while 构造更好:

            i = 0;
            do {
               // act
               i++;
            } while(i > 0);
          

          以下两个 sn-ps 循环 255 次,从 1 到 255。

            for(i = 1; i <= 255 && i != 0; i++)
          

          应该去。或者也许

             for(i = 1; i > 0; i++)
          

          【讨论】:

          • 当然,David Heffernan 是对的:在现代系统上,cpus 处理“int”而不是“char”更为自然。
          • 我们不应该使用 char 或 int 或 short 或其中任何一个。只是字节。
          • C 没有字节,只有 char(char == byte 可能);我已经修复了ans,因为旧版本循环了 255 次(1-255);当然我必须是无符号字符,否则循环会更长
          • 啊,我是 Java 菜鸟,所以我不知道。我只看过 C 并做了一些 C++
          • 在第二个和第三个解决方案中,在进入循环之前添加一个单独的迭代就足够了,正如另一个解决方案中所建议的那样:f(0); /* for loops with f(i) body */
          猜你喜欢
          • 2013-02-16
          • 1970-01-01
          • 1970-01-01
          • 2019-11-06
          • 1970-01-01
          • 2020-04-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多