Technical reasons behind formatting when increment

2020-01-27 02:02发布

All over the web, code samples have for loops which look like this:

for(int i = 0; i < 5; i++)

while I used the following format:

for(int i = 0; i != 5; ++i)

I do this because I believe it to be more efficient, but does this really matter in most cases?

30条回答
贼婆χ
2楼-- · 2020-01-27 02:38

I see plenty of answers using the specific code that was posted, and integer. However the question was specific to 'for loops', not the specific one mentioned in the original post.

I prefer to use the prefix increment/decrement operator because it is pretty much guaranteed to be as fast as the postfix operator, but has the possibility to be faster when used with non-primitive types. For types like integers it will never matter with any modern compiler, but if you get in the habit of using the prefix operator, then in the cases where it will provide a speed boost, you'll benefit from it.

I recently ran a static analysis tool on a large project (probably around 1-2 million lines of code), and it found around 80 cases where a postfix was being used in a case where a prefix would provide a speed benefit. In most of these cases the benefit was small because the size of the container or number of loops would usually be small, but in other cases it could potentially iterate over 500+ items.

Depending on the type of object being incremented/decremented, when a postfix occurs a copy can also occur. I would be curious to find out how many compilers will spot the case when a postfix is being used when its value isn't referenced, and thus the copy could not be used. Would it generate code in that case for a prefix instead? Even the static analysis tool mentioned that some of those 80 cases it had found might be optimized out anyway, but why take the chance and let the compiler decide? I don't find the prefix operator to be at all confusing when used alone, it only becomes a burden to read when it starts getting used, inline, as part of a logic statement:

int i = 5;
i = ++i * 3;

Having to think about operator precedence shouldn't be necessary with simple logic.

int i = 5;
i++;
i *= 3;

Sure the code above takes an extra line, but it reads more clearly. But with a for loop the variable being altered is its own statement, so you don't have to worry about whether it's prefix or postfix, just like in the code block above, the i++ is alone, so little thought is required as to what will happen with it, so this code block below is probably just as readable:

int i = 5;
++i;
i *= 3;

As I've said, it doesn't matter all that much, but using the prefix when the variable is not being used otherwise in the same statement is just a good habit in my opinion, because at some point you'll be using it on a non-primitive class and you might save yourself a copy operation.

Just my two cents.

查看更多
Root(大扎)
3楼-- · 2020-01-27 02:39

I switched to using != some 20+ years ago after reading Dijkstra's book called "A Discipline of Programming". In his book Dijkstra observed that weaker continuation conditions lead to stronger post-conditions in loop constructs.

For example, if we modify your construct to expose i after the loop, the post-condition of the fist loop would be i >= 5, while the post-condition of the second loop is a much stronger i == 5. This is better for reasoning about the program in formal terms of loop invariants, post-conditions, and weakest pre-conditions.

查看更多
不美不萌又怎样
4楼-- · 2020-01-27 02:39

I have decided to list the most informative answers as this question is getting a little crowded.

DenverCoder8's bench marking clearly deserves some recognition as well as the compiled versions of the loops by Lucas. Tim Gee has shown the differences between pre & post increment while User377178 has highlighted some of the pros and cons of < and !=. Tenacious Techhunter has written about loop optimizations in general and is worth a mention.

There you have my top 5 answers.

  1. DenverCoder8
  2. Lucas
  3. Tim Gee
  4. User377178
  5. Tenacious Techhunter
查看更多
该账号已被封号
5楼-- · 2020-01-27 02:40

In generic code you should prefer the version with != operator since it only requires your i to be equally-comparable, while the < version requires it to be relationally-comparable. The latter is a stronger requirement than the former. You should generally prefer to avoid stronger requrements when a weaker requirement is perfectly sufficient.

Having said that, in your specific case if int i both will work equally well and there won't be any difference in performance.

查看更多
啃猪蹄的小仙女
6楼-- · 2020-01-27 02:42

Everybody loves their micro-optimizations, but this would not make a difference as far as I can see. I compiled the two variations with g++ on for Intel processors without any fancy optimizations and the results are for

for(int i = 0; i < 5; i++)
    movl $0, -12(%ebp)
    jmp L2
L3:
    leal    -12(%ebp), %eax
    incl    (%eax)
L2:
    cmpl    $4, -12(%ebp)
    jle L3

for(int i = 0; i != 5; ++i)
    movl    $0, -12(%ebp)
    jmp L7
L8:
    leal    -12(%ebp), %eax
    incl    (%eax)
L7:
    cmpl    $5, -12(%ebp)
    jne L8

I think jle and jne should translate to equally fast instructions on most architectures. So for performance, you should not distinguish between the two. In general, I would agree that the first one is a little safer and I also think more common.


EDIT (2 years later): Since this thread recently got again a lot of attention, I would like to add that it will be difficult to answer this question generally. Which versions of code are more efficient is specifically not defined by the C-Standard [PDF] (and the same applies to C++ and probably also for C# ).

Section 5.1.2.3 Program execution

§1 The semantic descriptions in this International Standard describe the behavior of an abstract machine in which issues of optimization are irrelevant.

But it is reasonable to assume that a modern compiler will produce equally efficient code and I think that in only very rare cases will the loop-test and the counting expression be the bottleneck of a for-loop.

As for taste, I write

for(int i = 0; i < 5; ++i)
查看更多
一夜七次
7楼-- · 2020-01-27 02:42

If the increment rule changes slightly you immediately have an infinite loop. I much prefer the first end condition.

查看更多
登录 后发表回答