【问题标题】:For i = 0, why is (i += i++) equal to 0?对于 i = 0,为什么 (i += i++) 等于 0?
【发布时间】:2012-11-11 02:05:22
【问题描述】:

获取以下代码(可用作控制台应用程序):

static void Main(string[] args)
{
    int i = 0;
    i += i++;
    Console.WriteLine(i);
    Console.ReadLine();
}

i 的结果为 0。我预计为 2(正如我的一些同事所做的那样)。可能编译器会创建某种结构,导致i 为零。

我期望 2 的原因是,在我的思路中,右手边的语句将首先被评估,将 i 加 1。然后将它添加到 i。由于 i 已经是 1,所以它正在将 1 加到 1。所以 1 + 1 = 2。显然这不是正在发生的事情。

你能解释一下编译器做了什么或者在运行时发生了什么吗?为什么结果为零?

某种免责声明:我绝对知道您不会(并且可能不应该)使用此代码。我知道我永远不会。不过,我发现了解它为何以这种方式运行以及究竟发生了什么是很有趣的。

【问题讨论】:

  • 预期结果不应该是 1 吗? i(0) += i++(1) 因此 0 += 1 = 1
  • 它按预期工作
  • 这个问题将被问到多少种变体?
  • Preincrementation 会在执行动作之前增加值 i += ++i 会给你 1
  • 为什么每个人都关注前增量和后增量? “奇怪”的事情是 += 左侧的 i 的 value 在评估右侧之前被“缓存”。这是违反直觉的,例如,如果i 是一个对象,则需要进行复制操作。 (请不要误解我的意思:我绝对同意声明0 是正确且符合标准的答案。)

标签: c# .net


【解决方案1】:

这个:

int i = 0;
i += i++

可以看出你在做什么(以下是粗略的过度简化):

int i = 0;
i = i + i; // i=0 because the ++ is a postfix operator and hasn't been executed
i + 1; // Note that you are discarding the calculation result

实际发生的事情比这更复杂 - 看看 MSDN,7.5.9 Postfix increment and decrement operators:

x++ 或 x-- 形式的后缀递增或递减操作的运行时处理包括以下步骤:

  • 如果 x 被归类为变量:

    • x 被评估以产生变量。
    • x 的值被保存。
    • 选择的运算符以 x 的保存值作为参数调用。
    • 运算符返回的值存储在 x 求值给出的位置。
    • 保存的 x 值成为运算的结果。

请注意,由于order of precedence,后缀++ 出现在之前 +=,但结果最终未被使用(因为使用了i 的先前值)。


将i += i++ 更彻底地分解为组成它的部分需要知道+= 和++ 都不是原子的(也就是说,两者都不是单一操作),即使它们看起来就像他们一样。这些实现的方式涉及临时变量,在操作发生之前i 的副本 - 每个操作一个。 (我将分别使用名称 iAdd 和 iAssign 作为用于 ++ 和 += 的临时变量。

因此,更接近于正在发生的事情是:

int i = 0;
int iAdd = i; // Copy of the current value of i, for ++
int iAssign = i; // Copy of the current value of i, for +=

i = i + 1; // i++ - Happens before += due to order of precedence
i = iAdd + iAssign;

【讨论】:

  • @Oded ++ 操作在语句评估完成之前完成。所以+= 覆盖了这个值。这是怎么回事?
  • @Oded 实际上是:int i = 0; i = i + 1; (postfix) i = 0; (assignment)。如果您在该语句的其他地方使用了 i,则它当时的计算结果为 1。
  • @Cthulhu - 本质上。 dtb 的 answer 进入细节。
  • 我不买这个。 @yoriy 的回答要准确得多。一方面,在你的回答中,你说最后一行是i+1,而它应该是i=i+1。这不就是i++ 吗?
  • 答案的第一部分是多余的。恕我直言,您的最后一个代码示例可能已经完成了。虽然 +1。
【解决方案2】:

运行代码的反汇编:

int i = 0;
  xor         edx, edx
  mov         dword ptr i, edx         // set i = 0
i += i++;
  mov         eax, dword ptr i         // set eax = i (=0)
  mov         dword ptr tempVar1, eax  // set tempVar1 = eax (=0)
  mov         eax, dword ptr i         // set eax = 0 ( again... why??? =\ )
  mov         dword ptr tempVar2, eax  // set tempVar2 = eax (=0)
  inc         dword ptr i              // set i = i+1 (=1)
  mov         eax, dword ptr tempVar1  // set eax = tempVar1 (=0)
  add         eax, dword ptr tempVar2  // set eax = eax+tempVar2 (=0)
  mov         dword ptr i, eax         // set i = eax (=0)

等效代码

它编译为与以下代码相同的代码:

int i, tempVar1, tempVar2;
i = 0;
tempVar1 = i; // created due to postfix ++ operator
tempVar2 = i; // created due to += operator
++i;
i = tempVar1 + tempVar2;

第二个代码的反汇编(只是为了证明它们是相同的)

int i, tempVar1, tempVar2;
i = 0;
    xor         edx, edx
    mov         dword ptr i, edx
tempVar1 = i; // created due to postfix ++ operator
    mov         eax, dword ptr i
    mov         dword ptr tempVar1, eax
tempVar2 = i; // created due to += operator
    mov         eax, dword ptr i
    mov         dword ptr tempVar2, eax
++i;
    inc         dword ptr i
i = tempVar1 + tempVar2;
    mov         eax, dword ptr tempVar1
    add         eax, dword ptr tempVar2
    mov         dword ptr i, eax

打开反汇编窗口

大多数人不知道,甚至不记得,他们可以使用 Visual Studio 反汇编窗口看到最终的内存中汇编代码。它显示正在执行的机器代码,它不是 CIL。

在调试时使用它:

Debug (menu) -> Windows (submenu) -> Disassembly

那么 postfix++ 发生了什么?

postfix++ 告诉我们要在求值后增加操作数的值……大家都知道……有点混淆的是“在求值之后”的含义 .

那么“评估后”是什么意思:

  • 必须影响同一行代码中操作数的其他用法:
    • a = i++ + i第二个i受增量影响
    • Func(i++, i) 第二个 i 受到影响
  • 同一行的其他用法尊重短路运算符,如|| 和&&:
    • (false && i++ != i) || i == 0 第三个 i 不受 i++ 影响,因为它没有被评估

那么i += i++;是什么意思?

同i = i + i++;

求值顺序为:

  1. 存储 i + i(即 0 + 0)
  2. 递增 i(i 变为 1)
  3. 将第1步的值赋给i(i变为0)

并不是增量被丢弃。

i = i++ + i;是什么意思?

这与前面的示例不同。第三个i受增量影响。

求值顺序为:

  1. 存储i(即0)
  2. 递增 i(i 变为 1)
  3. 存储 step 1 + i 的值(即 0 + 1)
  4. 将第 3 步的值赋给 i(i 变为 1)

【讨论】:

  • +1++ - 纯粹的铁杆解剖。 Chuck Norris 会很自豪 :) 我猜你确实假设 OP 在 Intel 上,而不是 Mono 端口...
  • C# 有一个明确定义的表达式求值顺序,而目标代码只是实现了该顺序。机器码输出不是评估顺序的原因或解释。
  • 机器码便于理解 IMO 的求值顺序是如何实现的。
  • @StuartLC 我知道你在那里做了什么。不过,对被丢弃的赞成票感到羞耻。
  • a++ + a 与 a + a++ 不同,因为这不再是纯数学。代数中的交换律没有考虑变量在表达式中途改变值的可能性。只有当编程是函数式编程时,数学才能巧妙地映射到编程。由于代表性的限制,即使在那时也不是。例如,浮点数有时表现得像实数,有时则不是。即使没有副作用,适用于数学中实数的交换律和结合律也能打破浮点数。
【解决方案3】:
int i = 0;
i += i++;

评估如下:

Stack<int> stack = new Stack<int>();
int i;

// int i = 0;
stack.Push(0);                   // push 0
i = stack.Pop();                 // pop 0 --> i == 0

// i += i++;
stack.Push(i);                   // push 0
stack.Push(i);                   // push 0
stack.Push(i);                   // push 0
stack.Push(1);                   // push 1
i = stack.Pop() + stack.Pop();   // pop 0 and 1 --> i == 1
i = stack.Pop() + stack.Pop();   // pop 0 and 0 --> i == 0

即i 被更改了两次:一次是 i++ 表达式,一次是 += 语句。

但是+=语句的操作数是

  • 评估i++之前的值i(+=的左侧)和
  • i 在评估 i++ 之前的值(+= 的右侧)。

【讨论】:

  • 啊,这是一个很棒的解释。让我想起了我在使用反向波兰符号开发基于堆栈的计算器时。
【解决方案4】:

首先,i++ 返回 0。然后 i 加 1。最后,i 设置为 i 的初始值,即 0 加上返回的值 i++,这也是零。 0 + 0 = 0。

【讨论】:

  • 但是是i += i++;,而不是i = i++;,所以i++(0)的值加到i上,而不是"i设置为i++的值回来”。现在的问题是,当把i++ 返回到i 的值相加时,i 是增量值还是非增量值?我的朋友,答案写在规范中。
  • 没错,我会解决的。但无论如何,因为最初是i = 0,所以i += something 等价于i = 0 + something,即i = something。
【解决方案5】:

这只是抽象语法树的从左到右、自下而上的评估。从概念上讲,表达式的树是从上往下遍历的,但是当递归从底部弹出树时,求值就会展开。

// source code
i += i++;

// abstract syntax tree

     +=
    /  \
   i    ++ (post)
         \
         i

评估从考虑根节点+= 开始。这是表达式的主要组成部分。必须计算+= 的左操作数以确定我们存储变量的位置,并获得零的先验值。接下来,必须评估右侧。

右侧是一个后递增的++ 运算符。它有一个操作数i,它既可以作为值的来源,也可以作为存储值的位置。运算符评估i,找到0,然后将1 存储到该位置。它根据返回先验值的语义返回先验值0。

现在控制权又回到了+= 运算符。它现在拥有完成其操作的所有信息。它知道存储结果的位置(i的存储位置)以及先验值,并且它具有要添加到先验值的值,即0。所以,i 以零结尾。

与 Java 一样,C# 通过固定求值顺序对 C 语言的一个非常愚蠢的方面进行了清理。从左到右、自下而上:编码人员可能期望的最明显的顺序。

【讨论】:

  • +1:我同意你的看法,除了每个编码员都希望... ..当然我不再期待了。
  • 另外,我的预期不一致!它不等于 Set(ref i, Sum(i, Inc(ref i))) 与 int Set(ref int a, int b) { return a = b; } 和 int Sum(int a, int b) { return a + b; }。
  • 谢谢;您暗示我的答案存在缺陷/不完整,我必须修复。
  • SetSum 的问题在于它不评估左侧操作数 i,而只获取其地址,因此它不等同于对操作数进行从左到右的完整评估。你需要像SetSum(ref i, i, PostInc(ref i)) 这样的东西。 SetSum 的第二个参数是要添加的值,这里我们只使用i 指定i 的先验值。 SetSum 就是 int SetSum(ref int dest, int a, int b) { return dest = a + b; }。
  • += 运算符会发生混淆(至少对我来说),因为赋值运算符具有从右到左的评估(例如 a = b = c = d)......所以可以想象+= 遵循相同的规则,作为一个原子操作(就像我对我的 SetSum 方法所做的那样)...但实际上发生的是 C# 将 a += b 转换为 a = a + b... 表明 += 运算符不是原子...它只是语法糖。
【解决方案6】:

因为i++ 首先返回值,然后递增它。但是在 i 设置为 1 之后,你将它设置回 0。

【讨论】:

    【解决方案7】:

    后增量方法看起来像这样

    int ++(ref int i)
    {
        int c = i;
        i = i + 1;
        return c;
    }
    

    所以基本上当您调用i++ 时,i 是递增的,但在您的情况下返回原始值,返回的是 0。

    【讨论】:

      【解决方案8】:

      简单回答

      int i = 0;
      i += i++;
      // Translates to:
      i = i + 0; // because post increment returns the current value 0 of i
      // Before the above operation is set, i will be incremented to 1
      // Now i gets set after the increment,
      // so the original returned value of i will be taken.
      i = 0;
      

      【讨论】:

        【解决方案9】:

        i++ 表示:返回 i 的值 THEN 递增。

        i += i++ 表示: 取 i 的当前值。 将 i++ 的结果相加。

        现在,让我们添加 i = 0 作为起始条件。 i += i++ 现在的计算方式如下:

        1. i 的当前值是多少?它是 0。存储它,以便我们可以将 i++ 的结果添加到它。
        2. 计算 i++(计算为 0,因为这是 i 的当前值)
        3. 加载存储的值并将第 2 步的结果添加到其中。 (加 0 到 0)

        注意:在第 2 步结束时,i 的值实际上是 1。但是,在第 3 步中,您通过在 i 递增之前加载它的值来丢弃它。

        与 i++ 不同,++i 返回递增的值。

        因此,i+= ++i 会给你 1。

        【讨论】:

        • 全是帮助
        【解决方案10】:

        修复后增量运算符++ 在表达式中为变量提供一个值,然后执行增量您再次将返回的零 (0) 值分配给 i,这会覆盖增量的一 (1) ,所以你得到了零。您可以在 ++ Operator (MSDN) 中阅读有关增量运算符的更多信息。

        【讨论】:

          【解决方案11】:

          i += i++; 将等于 0,因为它会在之后执行 ++。

          i += ++i; 之前会这样做

          【讨论】:

          • 如果之后是++,我希望结果是1。
          【解决方案12】:

          ++ 后缀在递增之前评估i,而+= 只评估一次i。

          因此,0 + 0 = 0,因为i 在递增之前被评估和使用,因为使用了++ 的后缀格式。要首先增加 i,请使用前缀形式 (++i)。

          (另外,请注意:你应该只得到 1,因为 0 + (0 + 1) = 1)

          参考:http://msdn.microsoft.com/en-us/library/sa7629ew.aspx (+=)
          http://msdn.microsoft.com/en-us/library/36x43w8w.aspx (++)

          【讨论】:

            【解决方案13】:

            C# 在做什么,以及困惑的“原因”

            我也预计该值为 1...但对此问题的一些探索确实澄清了一些观点。

            考虑以下方法:

                static int SetSum(ref int a, int b) { return a += b; }
            
                static int Inc(ref int a) { return a++; }
            

            我预计i += i++ 与SetSum(ref i, Inc(ref i)) 相同。此语句后 i 的值为1:

            int i = 0;
            SetSum(ref i, Inc(ref i));
            Console.WriteLine(i); // i is 1
            

            但后来我得出另一个结论...i += i++ 实际上与i = i + i++ 相同...所以我创建了另一个类似的示例,使用这些函数:

                static int Sum(int a, int b) { return a + b; }
            
                static int Set(ref int a, int b) { return a = b; }
            

            调用Set(ref i, Sum(i, Inc(ref i)))后,i的值为0:

            int i = 0;
            Set(ref i, Sum(i, Inc(ref i)));
            Console.WriteLine(i); // i is 0
            

            这不仅解释了 C# 在做什么......而且解释了为什么很多人对它感到困惑......包括我。

            【讨论】:

            • 请将其添加到您的原始答案中,将其作为单独的答案并不会增加任何好处。
            • 我这样做不是为了污染其他答案,因为它是关于反编译的代码......而在这一个中,我尝试了一种不同的方法来解释事情。你怎么看?我应该编辑另一个答案并附加这个答案吗?也许,把这个放在前面……不知道!感谢您的建议!
            【解决方案14】:

            我一直记得的一个很好的助记词如下:

            如果++ 位于表达式之后,则它返回之前 的值。所以下面的代码

            int a = 1;
            int b = a++;
            

            是 1,因为a 之前是 1 它增加了 ++ 之后 a。人们将此称为post修复符号。还有一个 prefix 表示法,情况正好相反:如果 ++ 代表 before,则表达式返回它是 after 的值b> 操作:

            int a = 1;
            int b = ++a;
            

            b 是两个。

            所以对于您的代码,这意味着

            int i = 0;
            i += (i++);
            

            i++ 返回 0(如上所述),所以 0 + 0 = 0。

            i += (++i); // Here 'i' would become two
            

            Scott Meyers 在“有效的 C++ 编程”中描述了这两个符号之间的区别。在内部,i++(后缀)会记住值i,并调用前缀表示法(++i)并返回旧值i。这就是为什么你应该总是在for循环中使用++i(尽管我认为所有现代编译器都在for循环中将i++翻译成++i)。

            【讨论】:

            • 我测试了int i = 0; i += (++i),i 设置为一而不是二。这对我来说也很有意义,因为使用前缀而不是后缀并不会改变这样一个事实,即如果您将i += (++i) 写入i = i + (++i),则i 在++i 之前被评估,从而导致i = 0 + (++i)最终i = 0 + 1。
            【解决方案15】:

            您问题的唯一正确答案是:因为它是未定义的。

            好吧,在你们把我烧死之前……

            你们都回答了为什么i+=i++ 是可以的并且符合逻辑的结果是i=0。

            我很想对你的每一个答案都投反对票,但我计算出的声誉影响太高了..

            为什么我对你们这么生气?不是因为你的答案解释了什么..
            我的意思是,我读到的每一个答案都非常努力地解释了不可能的事情,我鼓掌!

            但是结果是什么?是直观的结果吗?是可以接受的结果吗?

            你们每个人都看到了“裸王”,并以某种方式接受它为理性的国王。

            你们都错了!

            i+=i++; 导致 0 未定义。

            如果你愿意的话,语言评估机制中的一个错误......甚至更糟!设计中的错误。

            想要证明吗?你当然想要!

            int t=0; int i=0; t+=i++; //t=0; i=1

            现在这...是直观的结果!因为我们首先评估 t 并为其分配了一个值,并且只有在评估和分配之后我们才进行后期操作 - 不是吗?

            是否合理:i=i++ 和 i=i 为 i 产生相同的结果?

            而t=i++ 和t=i 对i 有不同的结果。

            post 操作应该在语句评估之后发生。
            因此:

            int i=0;
            i+=i++;
            

            如果我们写应该是一样的:

            int i=0;
            i = i + i ++;
            

            因此等同于:

            int i=0;
            i= i + i;
            i ++;
            

            因此等同于:

            int i=0;
            i = i + i;
            i = i + 1;
            

            如果我们理性思考,任何不是1 的结果都表明编译器中的错误或语言设计中的错误 - 但是 MSDN 和许多其他来源告诉我们“嘿 - 这是未定义的!”

            现在,在我继续之前,即使我给出的这组例子也没有得到任何人的支持或认可。但是,按照直觉和理性的方式,这应该是结果。

            编码人员应该不知道程序集是如何编写或翻译的!

            如果以不尊重语言定义的方式编写 - 这是一个错误!

            最后我从维基百科复制了这个Increment and decrement operators:
            由于递增/递减运算符修改了它的操作数,在同一个表达式中多次使用这样的操作数可能会产生 undefined结果。例如,在 x − ++x 等表达式中,并不清楚应该按什么顺序执行减法和增量运算符。当编译器应用优化时,这种情况会变得更糟,这可能导致操作的执行顺序与程序员的预期不同。

            因此。

            正确的答案是不应该使用这个! (因为它是未定义的!)

            是的.. - 即使 C# 编译器试图以某种方式对其进行规范化,它也会产生不可预知的结果。

            我没有找到任何 C# 文档描述你们所有人都记录为该语言的正常或明确定义的行为。我发现的恰恰相反!

            [copied from MSDN documentation for Postfix Increment and Decrement Operators: ++ and --]

            当后缀运算符应用于函数参数时,参数的值不保证在传递给函数之前递增或递减。有关详细信息,请参阅 C++ 标准中的第 1.9.17 节。

            注意那些不保证...

            如果这个答案显得傲慢,请原谅我 - 我不是一个傲慢的人。我只是认为成千上万的人来这里学习,而我阅读的答案会误导他们,并会损害他们对主题的逻辑和理解。

            【讨论】:

            • 我不确定我是否 100% 关注,但您参考了 C++ 文档,但我的问题是关于 C#。相关文档是here。
            • 我在回答中指的是 C#。从您提供的链接中: x++ 或 x-- 的结果是操作前 x 的值,而 ++x 或 --x 的结果是操作后 x 的值。 在任何一种情况下,x 本身在操作后具有相同的值。 清楚地表明测试时不是这种情况。因为i=++i 将提供与i=i++ 不同的结果。因此,我的回答成立。
            • 啊哈,好的,但是当您参考 C++ 文档时会感到困惑。所以你的意思是规范没有正确实现?
            • 没有。我的意思是根据规范它是未定义的,使用未定义最终会得到未定义的结果。
            • 在 C++ 中未定义,但 C# 说它应该是操作后的值相同,不是吗?这与 undefined 不同(但我同意你不应该使用它,请参阅我的免责声明,我只是想了解发生了什么)。
            【解决方案16】:

            变量后的 ++ 运算符使其成为后缀增量。递增发生在语句中的所有其他内容、添加和赋值之后。相反,如果您将 ++ 放在变量之前,它将在 i 的值被评估之前发生,并给您预期的答案。

            【讨论】:

            • ++ 不会在+= 语句之后 发生,它会在+= 语句的执行期间 发生。这就是++ 的效果被+= 覆盖的原因。
            • 使用 ++i 实际上会得到 1,而不是 2(我最初的“预期答案”)。
            • 看起来赋值+=覆盖由于表达式中的前置或后置增量而导致的修改。
            【解决方案17】:

            计算步骤为:

            1. int i=0 //初始化为0
            2. i+=i++ //方程
            3. i=i+i++ //经过编译器简化后
            4. i=0+i++ //i 值替换
            5. i=0+0 //i++ 为 0,如下所述
            6. i=0 //最终结果 i=0

            这里,i 的初始值为 0。 WKT,i++ 只不过是:首先使用 i 值,然后将 i 值增加 1。所以 它在计算 i++ 时使用 i 值 0,然后将其递增 1。 所以它的结果是 0。

            【讨论】:

              【解决方案18】:

              有两种选择:

              第一种选择:如果编译器读取语句如下,

              i++;
              i+=i;
              

              那么结果是 2。

              对于

              else if
              i+=0;
              i++;
              

              结果是 1。

              【讨论】:

              • 两者都不是实际结果。
              【解决方案19】:

              要非常小心:阅读 C FAQ:您正在尝试做的事情(将同一变量的赋值和 ++ 混合)不仅未指定,而且也未定义(意味着编译器可能会做任何东西评估时!,不仅给出“合理”的结果)。

              请阅读,section 3。整个部分非常值得一读!尤其是 3.9,它解释了 unspecified 的含义。第 3.3 节简要总结了使用“i++”等可以做什么和不能做什么。

              根据编译器的内部结构,您可能会得到 0、2、或 1,甚至是其他任何值!而且由于它是未定义的,他们可以这样做。

              【讨论】:

              • 哎呀,c# ...我被“gcc”甩了,有些人通过反汇编代码。
              • 我也错过了它是 C#,但还是喜欢这个答案。
              • @Iain :谢谢,我也相信值得保留答案,很多人不知道这个(或者那个 great 常见问题解答,来自 Usenet 的最佳时间大多数对某个主题有知识的人都会去同一个地方更新它)
              【解决方案20】:

              上面的答案有很多很好的推理,我只是做了一个小测试,想和你分享

              int i = 0;
              i+ = i++;
              

              这里的结果 i 显示 0 结果。 现在考虑以下情况:

              案例一:

              i = i++ + i; //Answer 1
              

              之前我认为上面的代码与此类似,所以乍一看答案是 1,而 i 的真正答案是 1。

              案例 2:

              i = i + i++; //Answer 0 this resembles the question code.
              

              这里的自增操作符没有出现在执行路径中,这与之前 i++ 有机会在加法之前执行的情况不同。

              我希望这会有所帮助。谢谢

              【讨论】:

                【解决方案21】:

                希望从 C 编程 101 类型的角度回答这个问题。

                在我看来它是按照这个顺序发生的:

                1. i 被评估为 0,导致 i = 0 + 0 具有增量操作 i++“排队”,但尚未将 0 分配给 i。
                2. 发生增量i++
                3. 上面的赋值 i = 0 发生了,有效地覆盖了 #2(后增量)所做的任何事情。

                现在,#2 可能永远不会真正发生(可能不会?)因为编译器可能意识到它没有任何作用,但这可能取决于编译器。无论哪种方式,其他更有见识的答案都表明结果是正确的并且符合 C# 标准,但没有定义 C/C++ 此处发生的情况。

                如何以及为什么超出了我的专业知识,但之前评估的右侧赋值发生在后增量之后这一事实可能是这里令人困惑的地方。

                此外,除非您使用 ++i 而不是 i++ 我相信,否则您不会期望结果为 2。

                【讨论】:

                • 预增量版本使用 C++ 生成 2 的结果:ideone.com/8dH8tf
                • 这是有道理的。但与后增量相比,前增量的复杂程度略低。
                【解决方案22】:

                简单地说,

                i++,在“+=”运算符完成后将“i”加1。

                你想要的是 ++i,这样它就会在“+=”运算符执行之前将“i”加 1。

                【讨论】:

                  【解决方案23】:
                  i=0
                  
                  i+=i
                  
                  i=i+1
                  
                  i=0;
                  

                  然后将1添加到i。

                  i+=i++

                  所以在i 加 1 之前,i 取值为 0。只有我们之前加 1,i 才取值为 0。

                  i+=++i
                  
                  i=2
                  

                  【讨论】:

                    【解决方案24】:

                    答案是i 将是1。

                    让我们看看如何:

                    最初是i=0;。

                    然后在根据值计算i +=i++;时,我们会得到0 +=0++;,因此根据运算符优先级0+=0将首先执行,结果将是0。

                    然后增量运算符将应用为0++,0+1,i 的值将是1。

                    【讨论】:

                    • 这个答案是错误的。你不会得到 1,因为当你做 0 += 0++; 赋值是在增量 ++ 之后,但我的值在 ++ 之前解释(因为是一个 post 运算符。
                    • 对不起,这是不正确的。阅读我的问题,你会看到我说结果是 0。如果你运行代码,你会看到它实际上是 0。
                    猜你喜欢
                    • 2023-03-17
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-06-19
                    • 2011-06-14
                    • 1970-01-01
                    • 2019-03-11
                    • 2014-09-03
                    相关资源
                    最近更新 更多