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条回答
Melony?
2楼-- · 2020-01-27 02:30

We can use one more trick for this.

for (i = 5; i > 0; i--)

I suppose most of the compilers optimize the loops like this. I am not sure. Someone please verify.

查看更多
闹够了就滚
3楼-- · 2020-01-27 02:30

FORTRAN's DO loop and BASIC's FOR loop implemented < (actually <=) for positive increments. Not sure what COBOL did, but I suspect it was similar. So this approach was "natural" to the designers and users of "new" languages like C.

Additionally, < is more likely than != to terminate in erroneous situations, and is equally valid for integer and floating point values.

The first point above is the probable reason the style got started, the second is the main reason it continues.

查看更多
别忘想泡老子
4楼-- · 2020-01-27 02:31

Regarding readability. Being a C# programmer who likes Ruby, I recently wrote an extension method for int which allows the following syntax (as in Ruby):

4.Times(x => MyAction(x));
查看更多
Evening l夕情丶
5楼-- · 2020-01-27 02:34

The form

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

is idiomatic, so it's easier to read for experienced C programmers. Especially when used to iterate over an array. You should write idiomatic code whenever possible as it reads faster.

It is also a little safer in situations when you modify i inside the loop or use an increment different then 1. But it's a minor thing. It's best to carefully design your loop and add some asserts to catch broken assumptions early.

查看更多
▲ chillily
6楼-- · 2020-01-27 02:36

It depends on the language.

C++ texts often suggest the second format as that will work with iterators which can be compared (!=) directly but not with a greater to or less than condition. Also pre increment can be faster than post increment as there is no need for a copy of the variable for comparison - however optimisers can deal with this.

For integers either form works. The common idiom for C is the first one whilst for C++ it is the second.

For C# and Java use I would foreach to loop over all things.

In C++ there is also the std::for_each function requiring a use of a functor which for simple cases is probably more complex than either example here and the Boost FOR_EACH which can look like the C# foreach but is complex inside.

查看更多
迷人小祖宗
7楼-- · 2020-01-27 02:37

There's actually four permutations on what you give. To your two:

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

We can add:

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

On most modern machines with modern compilers it shouldn't be surprising that these will be of exactly the same efficiency. It could be just about possible that you may one day find yourself programming for some small processor where there's a difference between equality comparisons and less-than comparisons.

It may in some case make more sense to a particular mind with a particular case to think of "less than" or of "not equals" depending on the reason why we chose 0 and 5, but even then what makes one seem obvious to one coder may not with another.

More abstractly, these are of the forms:

for(someType i = start; i < end; i++)
for(someType i = start; i != end; ++i)
for(someType i = start; i < end; ++i)
for(someType i = start; i != end; i++)

An obvious difference here is that in two cases someType must have a meaning for < and for the rest it must have a meaning for !=. Types for which != is defined and < isn't are quite common, including quite a few iterator objects in C++ (and potentially in C# where the same approach as STL iterators is possible and sometimes useful, but neither as idiomatic, directly supported by common libraries nor as often useful since there are rival idioms with more direct support). It's worth noting that the STL approach is specifically designed so as to include pointers within the set of valid iterator types. If you're in the habit of using the STL you'll consider the forms with != far more idiomatic even when applied to integers. Personally a very tiny amount of exposure to it was enough to make it my instinct.

On the other hand, while defining < and not != would be rarer, it's applicable to cases where either we replace the increment with a different increase in i's value, or where i may be altered within the loop.

So, there's definite cases on both sides where one or the other is the only approach.

Now for ++i vs i++. Again with integers and when called directly rather than through a function that returns the result (and chances are even then) the practical result will be exactly the same.

In some C-style languages (those without operator over-loading) integers and pointers are about the only cases there is. We could just about artificially invent a case where the increment is called through a function just to change how it goes, and chances are the compiler will still turn them into the same thing anyway.

C++ and C# allow us to override them. Generally the prefix ++ operates like a function that does:

val = OneMoreThan(val);//whatever OneMoreThan means in the context.
//note that we assigned something back to val here.
return val;

And the postfix ++ operates like a function that does:

SomeType copy = Clone(val);
val = OneMoreThan(val);
return copy;

Neither C++ nor C# match the above perfectly (I quite deliberately made my pseudo-code match neither), but in either case there may be a copy or perhaps two made. This may or may not be expensive. It may or may not be avoidable (in C++ we often can avoid it entirely for the prefix form by returning this and in the postfix by returning void). It may or may not be optimised away to nothing, but it remains that it could be more efficient to do ++i than i++ in certain cases.

More particularly, there's the slight possibility of a slight performance improvement with ++i, and with a large class it could even be considerable, but barring someone overriding in C++ so that the two had completely different meanings (a pretty bad idea) it's not generally possible for this to be the other way around. As such, getting into the habit of favouring prefix over postfix means you might gain an improvement mayone one time in a thousand, but won't lose out, so it's a habit C++ coders often get into.

In summary, there's absolutely no difference in the two cases given in your question, but there can be in variants of the same.

查看更多
登录 后发表回答