是++ ++ ptr ++在c ++中的未定义行为?

SHM*_*SHM 56 c++ language-lawyer

我在测试中被问到以下问题(我不想自己编写.测试问它.我知道它的代码还不错)关于评估++*ptr ++

int Ar[ ] = { 6 , 3 , 8 , 10 , 4 , 6 , 7} ;
int *Ptr = Ar  ;
cout<<++*Ptr++  ;
Run Code Online (Sandbox Code Playgroud)

但是,我怀疑这是未定义的行为,因为它可以是(++*ptr)++或两者++(*ptr++).是吗?我不太熟悉文档,所以我找不到任何东西.

Mat*_*lia 76

但是我怀疑这是未定义的行为,因为它可以是(++*ptr)++或两者++(*ptr++).是吗?

事实并非如此,与运行时行为相比,它为实现者提供了充足的余地,在C++中,解析本身遵循非常严格且定义明确的规则1.的确,看着优先规则,++*Ptr++实际上是解析为++(*(Ptr++)).

这个技巧问题可能暗示了表达式的未定义行为,例如i = ++i + ++i,你有一个在表达式中多次出现的值,并且受到表达式本身的副作用的修改.这样的表达式是非法的,因为除非有一些运算符对副作用2进行排序,否则它们应用的确切时刻没有被定义,因此它未确切地定义i了表达式各个点中的值.

仍然,这里没有未定义的行为,因为表达式中的所有副作用都在不同的值上运行,这些值在表达式中只出现一次:"内部" ++影响Ptr,而外部影响最初指向的值Ptr,即Ar[0].

++(*(Ptr++))
     ^^^^^____increments Ptr, returning its original value
   ^^^^^^^^______dereferences the original Ptr, AKA &Ar[0]
^^^^^^^^^^^^_______ increments Ar[0]
Run Code Online (Sandbox Code Playgroud)

话虽这么说,如果我在我们的代码库中看到这样的表达式,我会竭尽全力找到作者,并确保不再发生这种情况.


  1. 如果有时实施起来非常奇怪且荒谬.不过,也描述解析的某些角落情况下在标准的未定义行为的情况下,但它的幅度比"运行"未定义行为那么普遍的订单.
  2. 这些规则的便利摘要可以在这里找到 ; 有趣的是,在C++ 17中添加了一些额外的保证.

  • @val:再次检查:这不合法.C++ 17刚刚为赋值和复合赋值运算符添加了一个序列点./sf/answers/3232036041/` ++ i + ++ i`即使只是自己也是非法的(左边没有赋值). (3认同)
  • @ruakh:最终,它是未定义的,因为标准说它未定义; 一个很好的合理化是标准为实现者留下了如此多的余地,无论何时他们都觉得最好,他们一路走下去并完全未定义以允许任何可能的优化(比如,存储一半的值)时刻和另一半之后,在此期间生成陷阱表示. (3认同)
  • @ruakh它是未定义的,因为它无法定义.它带有太多含糊之处.问题"为什么它未定义"是因为你无法定义它. (2认同)

Ach*_*hal 23

这个

++*Ptr++;
Run Code Online (Sandbox Code Playgroud)

不会导致UB并被评估为 ++(*(Ptr++))

  • ptr++; /* address post incremented i.e doesn't change here itself */
  • *ptr; /* dereference same address i.e value at location where ptr earlier pointed i.e 6 */
  • ++*ptr; /* value changed where ptr pointed i.e Ar[0] becomes 7 */

请注意,后增量Ptr++评估为

  • Ptr; /* Ptr doesn't change here itself in same expression */
  • Ptr = Ptr + 1; /* in next expression, Ptr considers the incremented one */