【问题标题】:Post-Increment Operator: Unexpected Behavior [duplicate]后增量运算符:意外行为 [重复]
【发布时间】:2011-03-17 17:24:52
【问题描述】:

可能重复:
Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)

我的代码如下:

#include <stdio.h>
int main()
{
  int x = 10, y = 0;
  x = x++;
  printf("x: %d\n", x);
  y = x++;
  printf("y: %d\n", y);
}

鉴于后增量的性质,我希望得到以下输出:

x: 10
y: 10

我的理由是在第 5 行中,x 应该在增量发生后分配给它的初始值。

然而,我得到了这个:

x: 11
y: 11

深入研究程序集,这对我来说似乎是一个深思熟虑的选择:

LCFI2:
        movl    $10, -4(%rbp)   // this is x
        movl    $0, -8(%rbp)    // this is y
        incl    -4(%rbp)        // x is simply incremented
        movl    -4(%rbp), %esi
        leaq    LC0(%rip), %rdi
        movl    $0, %eax
        call    _printf
        movl    -4(%rbp), %eax  // now x is saved in a register,
        movl    %eax, -8(%rbp)  // copied to y,
        incl    -4(%rbp)        // and finally incremented
        movl    -8(%rbp), %esi
        leaq    LC1(%rip), %rdi
        movl    $0, %eax
        call    _printf

这里发生了什么? GCC 是想把我从自己身边救出来吗?我没有方便的语言参考,但我认为这会破坏预期的语义。

【问题讨论】:

  • 在过去糟糕的日子里,a = 1 + a 在某些语言中是所有新错误都会踩到的地雷。
  • @caf - 你是对的,这是重复的(尽管不幸的是,这个问题没有提供任何有用的方法来搜索它)。
  • 当你说“但是,我得到这个:x = 11, y =11”时,你使用的是什么编译器。我检查了 codeblocks 和 onlinegdb,他们都给了我 x=10 , y = 10 正如预期的那样。

标签: c gcc post-increment


【解决方案1】:

行为未定义,因为x = x++ 中没有中间序列点,请参见例如C FAQ

【讨论】:

  • 谢谢!我以前不知道序列点。
【解决方案2】:

C 语言未定义确切的后/前/减量发生时间。因此,x = x++ 之类的语句格式不正确 - 避免使用它们。

【讨论】:

  • 更准确地说,您不允许在表达式中多次修改变量。 6.5/2:“在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的评估修改一次。”
  • @sth:更准确地说,“序列点之间不止一个”。表达式可能包含序列点,在这种情况下,多次修改变量是可以的。例如,&amp;&amp;|| 和逗号运算符都可以在单个表达式中形成序列点。
  • @sth:甚至更准确地说,这不是对编码器的限制,而是对变量本身的限制。您“不允许……”的说法并不完全正确。你允许,这只是一件非常愚蠢的事情:-)
  • 是的,我知道在那里使用“精确”这个词会引起一些后续的 cmets。但是已经很晚了,我懒得解释什么是序列点...... :)
【解决方案3】:

抛开标准(因为这在标准方面没有定义),它的运行方式是我所期望的。

我的经验法则是,对于带有x++ 的行,您将x++ 替换为x 并将x += 1 放在下一行(或前一行作为预增量)。

根据经验法则,您的代码将被编写为

#include <stdio.h>
int main()
{
  int x = 10, y = 0;
  x = x; // x: 10
  x += 1; // x: 11
  printf("x: %d\n", x);
  y = x; // y: 11
  x += 1; // x: 12
  printf("y: %d\n", y);
}

【讨论】:

    【解决方案4】:

    当你有:

    a = b++;
    

    发生的事情是 b 被保存到 a 并且在分配完成后 b 加一。所以如果你这样做:

    x = x ++;
    

    之前 x 是 10 会发生的是 10 将被保存到 x 之后(在您的 printf 完成之前)x 增加 1 到 11。这就是打印 11 的原因。

    【讨论】:

      猜你喜欢
      • 2016-02-02
      • 2013-09-16
      • 2023-03-26
      • 2012-11-23
      • 2020-07-14
      • 2010-12-29
      • 2010-10-14
      • 2012-07-18
      • 1970-01-01
      相关资源
      最近更新 更多