前缀自增 vs 后缀自增

7

我理解前置和后置自增的基础知识,但对于后置自增实际发生的时间仍有些困惑。

比如在下面的后置自增代码中:

int counter = 10;
int result = 0;

result = counter++ + 10;

cout << "Counter: " << counter << endl;
cout << "Result: " << result << endl;

我知道计数器将显示11,结果为20。结果为20是因为整个函数被执行,当程序走到返回0时,然后再加上+1。这个+1是什么时候加上的呢?
准确地说,+1是在return 0;语句执行之前加上的。
3个回答

6

什么时候会加上那个 +1?

根据 标准

++ 表达式的值计算在操作数对象修改之前。

从外行人的角度来看:

  1. counter 的计算是有序的,可能是语句的整个 RHS 的一部分,也可能只是术语 counter++
  2. counter += 1 的计算在程序中下一个语句之前被排序。

需要记住两件事:

  1. 术语的值——在表达式中它的求值结果。
  2. 术语求值的副作用。

对于 counter++ 的情况:

术语的值是在增加之前的 counter 的值。
评估术语的副作用是增加 counter 的值。


4
据我所知,赋值完成后就可以进行值的计算,不一定非得在计算值之后立即执行。 - eesiraed

4
此外,为了更好地理解,您可以考虑以下大致描述的例子:
  • the_typethe_object进行pre递增,就像执行以下函数:
the_object = the_object + 1;
return the_object;
  • 现在,将the_type类型的the_object进行后置递增,就像执行以下函数一样:
the_type backup_of_the_object;
backup_of_the_object = the_object;
the_object = the_object + 1;
return backup_of_the_object;

现在考虑:

result = counter++ + 10;

程序编译时:

  1. 编译器看到该行开头的 result =,因此它应该首先确定等号右侧放置了什么,然后生成将其分配给等号左侧的 result 的机器代码。
  2. 编译器看到 counter,但语句尚未结束,因为尚未到达;。所以现在它也知道必须对 counter 做些什么。
  3. 编译器看到 ++,但语句尚未结束。所以现在它知道必须考虑生成执行 counter++ 的机器代码。

  4. 编译器看到 +。所以现在它知道必须考虑生成将 + 右侧和 + 左侧(即 counter++)相加的机器代码。

  5. 编译器看到 10;,最终该语句已经结束。所以现在它知道所有需要知道的内容! 它知道在生成执行 counter++ 的机器代码之后,它应该生成将 10 加到 它的结果上的机器代码。然后它应该生成将 结果 分配给 result 的机器代码。

程序运行时:

  1. CPU 应该执行 counter++

现在,counter 加 1,因此它是 11,但它的结果 (counter++) 是 counter 的先前值,即 10

  1. CPU 应该执行 它的结果(counter++) + 10

现在,它的结果(它的结果(counter++) + 10) 是 它的结果(10 + 10),即 20

  1. CPU 应该执行 result = 它的结果(它的结果(counter++) + 10)

现在,result20

此外请注意,每个阶段所描述的只是 result = counter++ + 10; 这一行代码,无论之后会发生什么。也就是说,在之前。
cout << "Counter: " << counter << endl;
cout << "Result: " << result << endl;

很显然,在 main() 返回 0 之前。

我认为你应该轻松一点,通过编写和运行一些程序来学习它!

祝你好运!


3

后增运算符:后增运算符用于在执行完包含后增运算符的表达式后递增变量的值。在后增操作中,变量的值首先用于表达式,然后再递增。

因此,在你的情况下

result = counter++ + 10;

后置递增运算符在本语句中的使用是在使用它之后才会发生,显然它会在下一条语句中反映出来。


递增操作保证在值计算之后进行,但不一定在整个表达式求值之后进行。例如,在result更改之前或之后都可以执行。 - eesiraed
1
这将使得 foo(i++);,即未定义行为,变为已定义。 - Kostas
@Kosta 好的,有一些情况是未定义的,请查看这里 - Tejendra
1
@FeiXiang 函数参数的求值副作用是无序的。请参见此处 - Kostas
@Kosta 这是未定义行为,因为 x 在两个参数中都被使用了,其中一个参数是修改 x 的表达式。因此,第二个参数中的 x++ 的副作用与第一个参数中的 x 的值计算是无序的。你的函数只有一个参数,所以这里不适用。任何函数参数的值计算和副作用在函数中的任何语句执行之前都是有序的,因此即使你在函数中读取/修改 i,它仍然不是未定义行为。(意外删除了我的第一条评论) - eesiraed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接