【问题标题】:Is "*p = ++(*q)" undefined when p and q point to the same object?当 p 和 q 指向同一个对象时,“*p = ++(*q)”是否未定义?
【发布时间】:2011-04-04 00:47:23
【问题描述】:

在阅读了序列点之后,我了解到i = ++i 是未定义的。

那么这段代码怎么样:

int i;
int *p = &i;
int *q = &i;
 *p = ++(*q);           // that should also be undefined right?

假设 p 和 q 的初始化是否取决于某些(复杂的)条件。 并且它们可能像上述情况一样指向同一个对象。 会发生什么?如果未定义,我们可以使用什么工具来检测?

编辑:如果两个指针不应该指向同一个对象,我们可以使用 C99 限制吗? 是“严格”的意思吗?

【问题讨论】:

  • 一个该死的好问题! +1 来自我...嗯....
  • 为什么i = ++i; 未定义?编译器必须从 RHS 表达式中获取一些值来执行赋值,并且预增量运算符将始终返回递增 1 的存储值,因此结果应该是可预测的。如果是i = i++;,那么它将是未定义的。
  • @Praetorian :它未定义。请参阅:第 5 章:第 4 点:在前一个和下一个序列点之间,标量对象的存储值最多只能通过表达式的评估修改一次
  • @Praetorian:根据我对规则的理解,i=i=i+1; 将是未定义的,因为它两次写入一个变量而没有中间序列点。除此之外,我相信如果i 不是易失性的,编译器可以通过计算y+1 来评估x=++y,将其存储到x(对于赋值运算符),然后再增加y。在某些处理器上,上述序列需要三个指令,x=++y; 可能的最小值。

标签: c c99 operator-precedence sequence-points


【解决方案1】:

表达式与 i=++i 相同。唯一能检测到它的工具就是你的头。在 C 中,权力伴随着责任。

【讨论】:

    【解决方案2】:

    是的,这是未定义的行为——您对一个对象进行了两次修改,但它们之间没有序列点。不幸的是,自动检查这个非常困难——我能想到的最好的方法是在此之前添加assert(p != q),这至少会给出一个干净的运行时错误,而不是更糟糕的错误。在一般情况下,在编译时检查这一点是无法确定的。

    【讨论】:

      【解决方案3】:

      这是个好问题。您强调的一件事是“序列点”,引用自 site

      为什么您不能依赖以下表达式: a[i] = i++; 因为没有为赋值、自增或索引操作符指定序列点,所以你不知道自增对 i 的影响何时发生。

      此外,上面的表达式同样相同,所以行为是未定义,至于追踪它的工具,为零,肯定有splint举个例子,但它是 C 标准,所以也许我还没有听说过的工具中有一个隐藏选项,也许 Gimpel 的 PC Lint 或 Riverblade 的 Visual lint 可能会帮助你,尽管我承认它确实更不用说在这方面追踪未定义的行为了。

      顺便说一句,GCC 的编译器版本 4.3.3 有这个选项 -Wsequence-point 作为标记警告的一部分..这是在我的 Slackware 13.0 盒子上...

      它只是表明,代码可能肉眼看起来没问题,并且编译得很好,但以后可能会引起头痛,最好的方法是进行代码审查,以发现编译器可能无法选择的内容up on,那是最好的武器选择!

      【讨论】:

        【解决方案4】:

        第 5 章表达式

        第 4 点:

        除非另有说明,单个运算符的操作数和单个表达式的子表达式的求值顺序以及副作用发生的顺序是未指定的。 在前一个和下一个序列点之间,一个标量对象的存储值最多只能通过表达式的评估修改一次。此外,只能访问先前值以确定要存储的值。对于完整表达式的子表达式的每个允许排序,都应满足本段的要求;否则行为未定义。

        [ Example:
          i = v[i ++];           / / the behavior is undefined
          i = 7 , i++ , i ++;    / / i becomes 9
          i = ++ i + 1;          / / the behavior is undefined 
          i = i + 1;             / / the value of i is incremented
        —end example ]
        

        因此这是未定义的行为:

        int i;
        int *p = &i;
        int *q = &i;
        *p = ++(*q);   // Bad Line
        

        在“Bad Line”中,标量对象“i”在表达式计算期间不止一次更新。仅仅因为对象“i”被间接访问并不会改变规则。

        【讨论】:

        • 可能想说第5章什么的。
        • @Kinopiko:我给你两个猜测。
        • 非常感谢,但我不想做出两次猜测,或者根本就没有任何猜测。
        • @Kinopiko:在回答 C++ 问题时唯一引用的就是 C++ 标准。如果标准之间存在差异,我会指定确切的版本,但由于它们都相同,因此是多余的。
        • York:谢谢,我没有意识到这是一个 C++ 问题,或者在 C++ 问题的答案中唯一可能引用的就是这个。
        【解决方案5】:

        最好的工具不是检测,而是首先避免这种情况,那就是使用良好的编程习惯。避免副作用,每个作业不超过一次写入。没有错

        *q += 1;
        *p = *q;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-08-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-12-21
          • 2017-09-03
          • 1970-01-01
          相关资源
          最近更新 更多