【问题标题】:For Loop vs While LoopFor 循环与 While 循环
【发布时间】:2012-02-17 10:52:49
【问题描述】:

在我的设计与分析讲座中 算法讲师说 for 循环将比 while 循环花费更少的时间用于以下示例算法。

1.  for(int i=0;i<5;i++)
    {    
2.      print(i);    
    }

1.  int i=0;
2.  while(i<5)
    {    
3.      print(i);    
4.      i++;    
    }

他说编译器将读取 1. of while 5 次 line 2. 4 次因此总时间 5+4=9 但是在while循环的情况下。编译器将读取 1. 1 次,2. 5次,3次4次,4次4次。因此总时间 1+5+4+4 = 14time 请告诉我这是对的。 for循环比while循环快吗?

谢谢。

【问题讨论】:

  • 一个设置为优化速度的编译器可能只发出五次print(i) 并完全消除循环。在这两种情况下。
  • 在现实世界中,我们会查看代码的易读性并根据它选择forwhile。编译器将要么优化差异。或者现代机器上的差异是如此之小以至于可以忽略不计。使用让您的生活更轻松的软件,而不是计算机的“生活”。
  • 我很确定编译器只会读取每一行一次;)
  • 编译器将明确地每行只读取一次。由于它基本上是相同的一组指令以太方式,它在运行时应该没有区别。奇怪的导师。
  • @wali 问题出在您的问题描述中。这与编译器将读取什么以及读取多少次无关,而是它将生成的代码。在这种情况下,它可能与任何现代编译器都是相同的指令集,除了在第二种情况下您没有声明变量。

标签: loops language-agnostic compiler-construction for-loop while-loop


【解决方案1】:

至少对于 MSVC 16 (VS 2010),这两种情况下的代码几乎相同:

; Line 5
    xor esi, esi
$LL3@main:
; Line 6
    push    esi
    push    OFFSET ??_C@_03PMGGPEJJ@?$CFd?6?$AA@
    call    _printf
    inc esi
    add esp, 8
    cmp esi, 5
    jl  SHORT $LL3@main

同时

; Line 4
    xor esi, esi
$LL2@main:
; Line 6
    push    esi
    push    OFFSET ??_C@_03PMGGPEJJ@?$CFd?6?$AA@
    call    _printf
; Line 7
    inc esi
    add esp, 8
    cmp esi, 5
    jl  SHORT $LL2@main

代码in my Subversion repository

【讨论】:

  • 感谢您的理智。 (注意只有调试信息和标签名称不同)
【解决方案2】:

在所有现代编译器中,loop analysis 都是在较低级别的中间表示上完成的(即,当所有高级循环结构都扩展为标签和跳转时)。对于编译器来说,两个循环是绝对等价的。

【讨论】:

  • 我可以提供什么合乎逻辑的理由或证据来与他争论。
  • @wali,给他看两个版本的汇编输出,给这张幻灯片,在gccllvm 中展示相关的转换实现(它们是现代编译器的典型代表)。
【解决方案3】:

我将传递性能(提示:没有区别,请检查生成的 IR 或程序集以获取证据)但是 语法维护 有两个重要区别。

语法

i 变量的作用域不同。在for 的情况下,i 只能在for headerbody 中访问,而在while 的情况下,它在循环之后可用.作为一般规则,最好有更紧凑的范围,更少的变量in-flight意味着编码时需要担心的上下文更少。

维护

for 循环具有将所有迭代操作紧密组合在一起的巧妙优势,因此可以一次性检查它们并进行检查。

此外,在引入continue 语句时还有一个重要区别:

for(int i = 0; i != 10; ++i) {
  if (array[i] == nullptr) { continue; }
  // act on it
}


int i = 0;
while (i != 10) {
  if (array[i] == nullptr) { continue; }
  // act on it
  ++i;
}

while 的情况下,continue 的引入产生了一个错误:无限循环,因为不再实现计数器。

影响

for 循环对于常规 迭代模式更具可读性和全面性。更好的是,在 C++11 中的 range-for 语句:

for (Item const& item : collection) {
}

这里的迭代完全由编译器负责,所以你一定不会搞砸的! (这使得for_each 算法有点没有意义......我们可以希望旧的表单开始撤退)

推论:while 循环应该保留给不规则的迭代模式,这样它们将在代码审查期间和未来的维护者通过突出 不规则性 引起特别注意案例。

【讨论】:

    猜你喜欢
    • 2014-03-23
    • 2016-03-25
    • 2011-05-11
    • 2015-09-18
    • 1970-01-01
    • 2019-11-10
    • 1970-01-01
    • 1970-01-01
    • 2014-08-06
    相关资源
    最近更新 更多