【问题标题】:Is ++*ptr++ undefined behaviour in c++?++*ptr++ 在 C++ 中是未定义的行为吗?
【发布时间】:2019-05-21 07:22:54
【问题描述】:

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

int Ar[ ] = { 6 , 3 , 8 , 10 , 4 , 6 , 7} ;
int *Ptr = Ar  ;
cout<<++*Ptr++  ;

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

【问题讨论】:

  • C++ 对你做了什么让你觉得有必要这样做?
  • 当询问“未定义的行为”时,最好的方法是先查看文档。
  • @soham:一般来说,询问多个++ 实例的复杂交互等代表永远不应该编写的代码,会招来反对票。或者换一种说法,如果你要问它是否定义明确,不要这样写。
  • @soham 为什么你认为它是未定义的?如果您在问题中解释这一点,我认为您会得到更少的反对票。
  • @MatteoItalia 这是在测试中被问到的,先生……我不想自己写

标签: c++ language-lawyer


【解决方案1】:

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

并非如此,与运行时行为不同,它为实现者提供了充足的回旋余地,在 C++ 中,解析本身遵循非常严格且定义明确的规则1。确实,看precedence rules++*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]

话虽如此,如果我在我们的代码库中看到这样的表达方式,我会不遗余力地找到作者并确保不再发生这种情况。


  1. 如果有时实施起来非常奇怪且成本高得离谱。尽管如此,在描述解析的某些极端情况的标准中仍有个未定义行为的实例,但它比“运行时”未定义行为普遍要少几个数量级。
  2. 这些规则的方便总结can be found here;有趣的是,在 C++17 中添加了一些额外的保证。

【讨论】:

  • @val 是什么让它合法?
  • i = ++i + ++i 的行为在 C++17 中未定义
  • @val:刚刚再次检查:这是不合法的。 C++17 刚刚为赋值和复合赋值运算符添加了一个序列点。 stackoverflow.com/a/46171943/214671 ++i + ++i 本身仍然是非法的(左侧没有赋值)。
  • @ruakh 未定义,因为无法定义。它带有太多的歧义。 “为什么它未定义”的问题是因为您无法定义它。
  • @ruakh:最终,它是未定义的,因为标准说它是未定义的;一个很好的合理化是,该标准为实现者留下了很大的余地,可以随时随地应用副作用,但他们觉得最好,他们一路走来并完全未定义以允许任何可能的优化(例如,在某些地方存储一半的值一会儿和另一半之后,同时生成一个陷阱表示)。
【解决方案2】:

这个

++*Ptr++;

不会导致 U.B 并被评估为++(*(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 */

【讨论】:

    猜你喜欢
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-25
    • 1970-01-01
    • 2018-05-03
    • 2014-05-01
    相关资源
    最近更新 更多