【问题标题】:Difference between sequence points and operator precedence? 0_o序列点和运算符优先级之间的区别? 0_o
【发布时间】:2011-09-21 21:11:48
【问题描述】:

让我举个例子:

a = ++a;

据说上面的语句有未定义的行为(我已经在SO上阅读了关于UB的文章)

但根据优先规则运算符前缀++的优先级高于赋值运算符=

所以a 应该首先增加然后分配回a。所以每一个评价都是已知的,那为什么是UB呢?

【问题讨论】:

  • 只是为了好玩,显然在 C++11 中,该语句似乎被完美定义,与 a = a++; (stackoverflow.com/questions/4176328/…) 不同。能够大喊“未定义的行为”会更有趣,但现在必须更加小心......
  • ++a 不保证先设置a,然后返回新值。只有 a 将设置在下一个序列点之前的某个时间,并且将返回 a + 1。

标签: c++


【解决方案1】:

这里要理解的重要一点是,运算符可以产生值,也可以有副作用。

例如++a 产生(计算为)a + 1,但它也有增加a 的副作用。 a = 5 也是如此(计算为 5,同时将 a 的值设置为 5)。

所以这里有两个副作用,它们改变了a 的值,都发生在序列点之间(可见分号和前一条语句的结尾)。

由于运算符优先级,两个运算符的计算顺序是明确定义的,因为处理它们的副作用的顺序仍未定义。

因此是 UB。

【讨论】:

  • 不得不来这里说声谢谢! “没关系……”这完全解决了我的困惑。谢谢!
【解决方案2】:

优先级是解析表达式的语法规则的结果。 ++ 比= 具有更高优先级的事实仅意味着++ 绑定到它的操作数比=“更紧密”。实际上,在您的示例中,由于运算符出现的顺序,只有一种方法可以解析表达式。在a = b++ 等示例中,语法规则或优先级保证这与a = (b++) 的含义相同,而不是(a = b)++。

优先级与表达式的计算顺序或表达式副作用的应用顺序几乎没有关系。 (显然,如果一个运算符根据语法规则或优先级对另一个表达式进行操作,则必须先计算该表达式的值,然后才能应用该运算符,但大多数独立子表达式可以按任何顺序和侧面计算 -效果也可以按任意顺序处理。)

【讨论】:

    【解决方案3】:

    为什么是UB?

    因为这是尝试在一个序列点之前将变量a 更改两次:

    • ++一个
    • 操作员=

    【讨论】:

    • 我已经知道了,但是有什么区别呢? -> 考虑运算符优先级有什么问题,为什么他们在这里错了?
    • 第一次做什么都没有关系,如果它导致未定义的行为
    【解决方案4】:

    序列点评估#6:在初始化程序的末尾;例如,在声明 int a = 5; 中评估 5 之后。来自维基百科。

    您尝试将同一个变量 a 更改两次。 ++a 改变它,赋值 (=) 改变它。但是序列点直到分配结束才完成。因此,虽然这对我们来说完全有意义 - 但标准并不能保证给出正确的行为,因为标准规定不要在序列点中多次更改某些内容(简单地说)。

    【讨论】:

      【解决方案5】:

      这有点微妙,但可以解释为以下之一(编译器不知道是哪一个:

      a=(a+1);a++;
      a++;a=a;
      

      这是因为语法有歧义。

      【讨论】:

      • 虽然 C++ 的语法在某些地方是模棱两可的,但这不是其中之一。 a = ++a; 的解析是完全明确的,只是行为没有定义。
      • 是的,但是语法的语义是模棱两可的,因此是未定义的行为。
      • 我不确定您所说的“语法语义”到底是什么意思。该表达式具有明确未定义的行为,我不认为有任何歧义。
      • 语义不明确,无法定义,因此称为未定义行为。如果没有歧义,那么它将被定义为行为。
      • 我不禁想到,我们一定是为了不同的目的而争论;这可能是因为我们不同意一些基本术语的定义。
      猜你喜欢
      • 2020-12-03
      • 2013-09-30
      • 2011-10-22
      • 2011-06-21
      • 2020-03-05
      • 1970-01-01
      • 2020-11-14
      • 1970-01-01
      • 2017-12-24
      相关资源
      最近更新 更多