如果在for循环中使用<或<=

Eug*_*atz 122 performance readability conventions

如果你不得不循环7次循环,你会使用:

for (int i = 0; i < 7; i++)
Run Code Online (Sandbox Code Playgroud)

要么:

for (int i = 0; i <= 6; i++)
Run Code Online (Sandbox Code Playgroud)

有两个注意事项:

  • 性能
  • 可读性

为了性能,我假设Java或C#.使用"小于"或"小于或等于"是否重要?如果您对其他语言有所了解,请说明哪些语言.

为了便于阅读,我假设基于0的数组.

UPD:我提到的基于0的数组可能会让人感到困惑.我不是在讨论迭代数组元素.只是一个循环.

关于使用常数可以解释这个神奇数字是什么,下面有一个好点.所以,如果我有" int NUMBER_OF_THINGS = 7"然后" i <= NUMBER_OF_THINGS - 1"看起来很奇怪,不会.

Jon*_*eet 287

第一个是更惯用的.特别是,它表示(基于0的意义上)迭代次数.当使用基于1的东西(例如JDBC,IIRC)时,我可能会想要使用<=.所以:

for (int i=0; i < count; i++) // For 0-based APIs

for (int i=1; i <= count; i++) // For 1-based APIs
Run Code Online (Sandbox Code Playgroud)

我希望现实代码中的性能差异微不足道.

  • 你几乎可以保证不会有性能差异.许多体系结构,如x86,在"最后比较"中的"跳跃小于或等于"指令.您看到性能差异的最可能方式是某种解释性语言实施不当. (30认同)
  • 我通常不会.这太陌生了.如果有人在循环期间意外地增加了i,它也会冒很长很长的循环. (21认同)
  • 使用STL迭代器进行通用编程需要使用!=.它(意外的双倍增量)对我来说不是问题.我同意,对于指数<(或>降序)更清晰和传统. (5认同)
  • 你会考虑使用!=吗?我会说,最清楚的是我把它作为一个循环计数器而没有别的. (3认同)
  • 请记住,如果使用<循环数组的长度,则JIT优化数组访问(删除绑定的检查).所以使用<=应该更快.我没有检查过它 (2认同)

Ste*_*osh 72

这两个循环都迭代7次.我会说一个带有7的人更可读/更清楚,除非你有另一个非常好的理由.


Mar*_*own 55

我记得在我808年大学集会的时候,我的表现更为出色:

for (int i = 6; i > -1; i--)
Run Code Online (Sandbox Code Playgroud)

因为有一个JNS操作意味着如果没有签名则跳转.使用这意味着在每个循环之后没有内存查找来获得比较值,也没有比较.现在大多数编译器都会优化寄存器的使用,因此内存不再重要,但仍然会得到一个不需要的比较.

顺便把7或6放在你的循环中引入一个" 神奇的数字 ".为了更好的可读性,您应该使用具有Intent Revealing Name的常量.像这样:

const int NUMBER_OF_CARS = 7;
for (int i = 0; i < NUMBER_OF_CARS; i++)
Run Code Online (Sandbox Code Playgroud)

编辑:人们没有得到装配的东西,所以显然需要一个更全面的例子:

如果我们这样做(i = 0; i <= 10; i ++),你需要这样做:

    mov esi, 0
loopStartLabel:
                ; Do some stuff
    inc esi
                ; Note cmp command on next line
    cmp esi, 10
    jle exitLoopLabel
    jmp loopStartLabel
exitLoopLabel:
Run Code Online (Sandbox Code Playgroud)

如果我们这样做(int i = 10; i> -1; i--)那么你可以逃脱这个:

    mov esi, 10
loopStartLabel:
                ; Do some stuff
    dec esi
                ; Note no cmp command on next line
    jns exitLoopLabel
    jmp loopStartLabel
exitLoopLabel:
Run Code Online (Sandbox Code Playgroud)

我刚刚检查过,微软的C++编译器没有进行这种优化,但是如果你这样做的话,它会这样做:

for (int i = 10; i >= 0; i--) 
Run Code Online (Sandbox Code Playgroud)

所以,道德是如果你使用Microsoft C++†,升序或降序没有区别,为了得到一个快速循环你应该使用:

for (int i = 10; i >= 0; i--)
Run Code Online (Sandbox Code Playgroud)

而不是其中任何一个:

for (int i = 10; i > -1; i--)
for (int i = 0; i <= 10; i++)
Run Code Online (Sandbox Code Playgroud)

但坦率地说,获得"for(int i = 0; i <= 10; i ++)"的可读性通常比丢失一个处理器命令重要得多.

†其他编译器可能会做不同的事情.

  • 另一个版本是"for(int i = 10; i--;)".有些人使用"for(int i = 10; i - > 0;)"并假装组合 - >意味着去. (11认同)
  • "神奇数字"案例很好地说明了为什么通常使用<than <=更好. (4认同)
  • 汇编代码为+1 (2认同)

Oma*_*eji 27

我总是使用<array.length,因为它比<= array.length-1更容易阅读.

也有<7,并且假设你知道它以0索引开始,那么这个数字应该是直观的迭代次数.

  • @Martin Brown:在Java中(我相信C#),String.length和Array.length是常量,因为String是不可变的,而Array具有不可变长度.由于String.length和Array.length是一个字段(而不是函数调用),因此可以确定它们必须是O(1).在C++的情况下,为什么你最初在使用C-string呢? (2认同)

erl*_*ndo 18

从优化的角度来看,它并不重要.

从代码风格的角度来看,我更喜欢<.原因:

for ( int i = 0; i < array.size(); i++ )
Run Code Online (Sandbox Code Playgroud)

比...更具可读性

for ( int i = 0; i <= array.size() -1; i++ )
Run Code Online (Sandbox Code Playgroud)

还<直接给你迭代次数.

对<的另一个投票是你可以防止很多意外的一对一错误.


Jef*_* Mc 10

@Chris,你关于.Length在.NET中代价高昂的说法实际上是不真实的,而在简单类型的情况下恰恰相反.

int len = somearray.Length;
for(i = 0; i < len; i++)
{
  somearray[i].something();
}
Run Code Online (Sandbox Code Playgroud)

实际上比...慢

for(i = 0; i < somearray.Length; i++)
{
  somearray[i].something();
}
Run Code Online (Sandbox Code Playgroud)

后者是由运行时优化的案例.由于运行时可以保证i是数组的有效索引,因此不会进行边界检查.在前者中,运行时不能保证在循环之前没有修改i,并强制对数组进行每次索引查找的边界检查.


Phi*_*ght 6

在性能方面,它没有任何有效的区别.因此,我会在您正在解决的问题的上下文中使用哪个更容易理解.


Dom*_*ger 5

我更喜欢:

for (int i = 0; i < 7; i++)
Run Code Online (Sandbox Code Playgroud)

我认为这更容易转换为"循环迭代7次".

我不确定性能影响 - 我怀疑任何差异都会被编译掉.


小智 5

在 C++ 中,我更喜欢使用!=,它可用于所有 STL 容器。并非所有 STL 容器迭代器都无法比较。

  • 如果您的代码中存在这样的错误,那么崩溃和烧毁可能比默默地继续要好:-) (2认同)