C++ “for”循环中的后增量和预增量产生相同的输出

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4706199/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:12:49  来源:igfitidea点击:

Post-increment and pre-increment within a 'for' loop produce same output

c++cfor-loopoperator-precedence

提问by theReverseFlick

The following for loops produce identical results even though one uses post increment and the other pre-increment.

即使一个使用后增量和另一个预增量,以下 for 循环也会产生相同的结果。

Here is the code:

这是代码:

for(i=0; i<5; i++) {
    printf("%d", i);
}

for(i=0; i<5; ++i) {
    printf("%d", i);
}

I get the same output for both 'for' loops. Am I missing something?

对于两个“for”循环,我得到相同的输出。我错过了什么吗?

回答by danben

After evaluating i++or ++i, the new value of iwill be the same in both cases. The difference between pre- and post-increment is in the result of evaluating the expression itself.

评估i++or 后++i, 的新值i在两种情况下都相同。前增量和后增量之间的区别在于评估表达式本身的结果。

++iincrements iand evaluates to the new value of i.

++i递增i并计算为 的新值i

i++evaluates to the old value of i, and increments i.

i++计算为 的旧值i,并递增i

The reason this doesn't matter in a for loop is that the flow of control works roughly like this:

这在 for 循环中无关紧要的原因是控制流的工作方式大致如下:

  1. test the condition
  2. if it is false, terminate
  3. if it is true, execute the body
  4. execute the incrementation step
  1. 测试条件
  2. 如果为假,则终止
  3. 如果为真,则执行主体
  4. 执行增量步骤

Because (1) and (4) are decoupled, either pre- or post-increment can be used.

因为 (1) 和 (4) 是解耦的,所以可以使用前置或后置增量。

回答by jason

Well, this is simple. The above forloops are semantically equivalent to

嗯,这很简单。上面的for循环在语义上等同于

int i = 0;
while(i < 5) {
    printf("%d", i);
    i++;
}

and

int i = 0;
while(i < 5) {
    printf("%d", i);
    ++i;
}

Note that the lines i++;and ++i;have the same semantics FROM THE PERSPECTIVE OF THIS BLOCK OF CODE. They both have the same effect on the value of i(increment it by one) and therefore have the same effect on the behavior of these loops.

请注意,从代码块的角度来看,行i++;++i;具有相同的语义。它们都对i(将其增加 1)的值具有相同的影响,因此对这些循环的行为具有相同的影响。

Note that there would be a difference if the loop was rewritten as

请注意,如果将循环重写为

int i = 0;
int j = i;
while(j < 5) {
    printf("%d", i);
    j = ++i;
}

int i = 0;
int j = i;
while(j < 5) {
    printf("%d", i);
    j = i++;
}

This is because in first block of code jsees the value of iafter the increment (iis incremented first, or pre-incremented, hence the name) and in the second block of code jsees the value of ibefore the increment.

这是因为在第一个代码块中j看到i增量之后的值(i首先增加,或预先增加,因此得名),而在第二个代码块中j看到i增量之前的值。

回答by Anders Sj?qvist

The result of your code will be the same. The reason is that the two incrementation operations can be seen as two distinct function calls. Both functions cause an incrementation of the variable, and only their return values are different. In this case, the return value is just thrown away, which means that there's no distinguishable difference in the output.

您的代码的结果将是相同的。原因是这两个递增操作可以看作是两个不同的函数调用。这两个函数都会引起变量的递增,只是它们的返回值不同。在这种情况下,返回值只是被丢弃了,这意味着输出中没有可区分的差异。

However, under the hoodthere's a difference: The post-incrementation i++needs to create a temporary variableto store the original value of i, then performs the incrementation and returns the temporary variable. The pre-incrementation ++idoesn't create a temporary variable. Sure, any decent optimization setting should be able to optimize this away when the object is something simple like an int, but remember that the ++-operators are overloaded in more complicated classes like iterators. Since the two overloaded methods might have different operations (one might want to output "Hey, I'm pre-incremented!" to stdout for example) the compiler can't tell whether the methods are equivalent when the return value isn't used (basically because such a compiler would solve the unsolvable halting problem), it needs to use the more expensive post-incrementation version if you write myiterator++.

但是,在幕后有一个区别:后增量i++需要创建一个临时变量来存储 的原始值i,然后执行增量并返回临时变量。预增量++i不会创建临时变量。当然,当对象很简单时,任何体面的优化设置都应该能够将其优化掉int,但请记住 ++ 运算符在更复杂的类(如迭代器)中被重载。由于这两个重载方法可能有不同的操作(例如,一个可能想要输出“嘿,我是预先递增的!”到标准输出),编译器无法在不使用返回值时判断这些方法是否等效(主要是因为这样的编译器会解决无法解决的停机问题),如果您编写myiterator++.

Three reasons why you should pre-increment:

您应该预先递增的三个原因:

  1. You won't have to think about whether the variable/object might have an overloaded post-incrementation method (for example in a template function) and treat it differently (or forget to treat it differently).
  2. Consistent code looks better.
  3. When someone asks you "Why do you pre-increment?" you'll get the chance to teach them about the halting problem and theoretical limits of compiler optimization. :)
  1. 您不必考虑变量/对象是否可能具有重载的后增量方法(例如在模板函数中)并对其进行不同的处理(或忘记对其进行不同的处理)。
  2. 一致的代码看起来更好。
  3. 当有人问你“你为什么要预先递增?” 您将有机会向他们教授编译器优化的停机问题和理论限制。:)

回答by Adam Liss

This is one of my favorite interview questions. I'll explain the answer first, and then tell you why I like the question.

这是我最喜欢的面试问题之一。我会先解释答案,然后告诉你为什么我喜欢这个问题。

Solution:

解决方案:

The answer is that both snippets print the numbers from 0 to 4, inclusive. This is because a for()loop is generally equivalent to a while()loop:

答案是两个片段都打印了从 0 到 4(包括 0 到 4)的数字。这是因为for()循环通常等同于while()循环:

for (INITIALIZER; CONDITION; OPERATION) {
    do_stuff();
}

Can be written:

可以写成:

INITIALIZER;
while(CONDITION) {
    do_stuff();
    OPERATION;
}

You can see that the OPERATION is alwaysdone at the bottom of the loop. In this form, it should be clear that i++and ++iwill have the same effect: they'll both increment iand ignore the result. The new value of iis not tested until the next iteration begins, at the top of the loop.

您可以看到 OPERATION始终在循环的底部完成。在这种形式中,应该很清楚i++++i将具有相同的效果:它们都会增加i并忽略结果。的新值i直到下一次迭代开始,在循环的顶部才被测试。



Edit: Thanks to Jason for pointing out that this for()to while()equivalence does nothold if the loop contains control statements (such as continue) that would prevent OPERATIONfrom being executed in a while()loop. OPERATIONis alwaysexecuted just before the next iteration of a for()loop.

编辑:感谢贾森指出,这for()while()等价并没有如果循环包含控制语句(如持有continue),这将防止OPERATION从一个执行while()循环。 OPERATION永远只是一个下一次迭代之前执行for()循环。



Why it's a Good Interview Question

为什么这是一个很好的面试问题

First of all, it takes only a minute or two if a candidate tells the the correct answer immediately, so we can move right on to the next question.

首先,如果候选人立即说出正确答案,只需一两分钟,这样我们就可以直接进入下一个问题。

But surprisingly (to me), many candidates tell me the loop with the post-increment will print the numbers from 0 to 4, and the pre-increment loop will print 0 to 5, or 1 to 5. They usually explain the difference between pre- and post-incrementing correctly, but they misunderstand the mechanics of the for()loop.

但令人惊讶的是(对我而言),许多候选人告诉我,带有后增量的循环将打印从 0 到 4 的数字,而前增量循环将打印 0 到 5,或 1 到 5。他们通常会解释两者之间的区别前后递增正确,但他们误解了for()循环的机制。

In that case, I ask them to rewrite the loop using while(), and this really gives me a good idea of their thought processes. And that's why I ask the question in the first place: I want to know how they approach a problem, and how they proceed when I cast doubt on the way their world works.

在这种情况下,我要求他们使用 重写循环while(),这确实让我对他们的思维过程有了很好的了解。这就是我首先提出这个问题的原因:我想知道他们如何解决问题,以及当我对他们的世界运作方式产生怀疑时他们如何进行。

At this point, most candidates realize their error and find the correct answer. But I had one who insisted his original answer was right, then changed the way he translated the for()to the while(). It made for a fascinating interview, but we didn't make an offer!

在这一点上,大多数考生意识到自己的错误并找到了正确的答案。但我有一个谁坚持他原来的答案是正确的,那么改变他翻译的方式for()while()。这是一次引人入胜的采访,但我们没有提供报价!

Hope that helps!

希望有帮助!

回答by tvanfosson

Because in either case the increment is done after the body of the loop and thus doesn't affect any of the calculations of the loop. If the compiler is stupid, it might be slightly less efficient to use post-increment (because normally it needs to keep a copy of the prevalue for later use), but I would expect any differences to be optimized away in this case.

因为在任何一种情况下,增量都是在循环体之后完成的,因此不会影响循环的任何计算。如果编译器很笨,那么使用后增量的效率可能会稍低一些(因为通常它需要保留pre值的副本以备后用),但我希望在这种情况下可以优化任何差异。

It might be handy to think of how the for loop is implemented, essentially translated into a set of assignments, tests, and branch instructions. In pseudo-code the pre-increment would look like:

考虑一下 for 循环是如何实现的,本质上是转换为一组赋值、测试和分支指令可能会很方便。在伪代码中,预增量看起来像:

      set i = 0
test: if i >= 5 goto done
      call printf,"%d",i
      set i = i + 1
      goto test
done: nop

Post-increment would have at least another step, but it would be trivial to optimize away

后增量至少还有一个步骤,但是优化掉是微不足道的

      set i = 0
test: if i >= 5 goto done
      call printf,"%d",i
      set j = i   // store value of i for later increment
      set i = j + 1  // oops, we're incrementing right-away
      goto test
done: nop

回答by iss42

If you wrote it like this then it would matter :

如果你这样写,那就很重要了:

for(i=0; i<5; i=j++) {
    printf("%d",i);
}

Would iterate once more than if written like this :

比这样写会迭代一次:

for(i=0; i<5; i=++j) {
    printf("%d",i);
}

回答by Yola

You could read Google answer for it here: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Preincrement_and_Predecrement

您可以在此处阅读 Google 的答案:http: //google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Preincrement_and_Predecrement

So, main point is, what no difference for simple object, but for iterators and other template objects you should use preincrement.

所以,重点是,简单对象没有什么区别,但是对于迭代器和其他模板对象,您应该使用预增量。

EDITED:

编辑:

There are no difference because you use simple type, so no side effects, and post- or preincrements executed after loop body, so no impact on value in loop body.

没有区别,因为你使用的是简单类型,所以没有副作用,并且在循环体之后执行后或预增量,所以对循环体中的值没有影响。

You could check it with such a loop:

你可以用这样的循环检查它:

for (int i = 0; i < 5; cout << "we still not incremented here: " << i << endl, i++)
{
    cout << "inside loop body: " << i << endl;
}

回答by Petruza

The third statement in the for construct is only executed, but its evaluated value is discarded and not taken care of.
When the evaluated value is discarded, pre and post increment are equal.
They only differ if their value is taken.

for 结构中的第三条语句只被执行,但它的评估值被丢弃而不被处理。
当评估值被丢弃时,前后增量相等。
只有当它们的值被采用时它们才会不同。

回答by Hoàng Long

Both i++ and ++i is executed after printf("%d", i) is executed at each time, so there's no difference.

i++ 和 ++i 都是在每次执行 printf("%d", i) 之后执行的,所以没有区别。

回答by Nawaz

Yes, you'll get exactly same outputs for both. why do you think they should give you different outputs?

是的,您将获得完全相同的输出。为什么你认为他们应该给你不同的输出?

Post-increment or pre-increment matters in situations like this:

在这样的情况下,后增量或前增量很重要:

int j = ++i;
int k = i++;
f(i++);
g(++i);

where you provide some value, either by assigning or by passing an argument. You do neither in your forloops. It gets incremented only. Post- and pre- don't make sense there!

您可以通过分配或传递参数来提供一些值。你在你的for循环中都不做。它只会增加。后和前在那里没有意义!