当p和q指向同一个对象时,“* p = ++(* q)”是否未定义?

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

那么这段代码怎么样:

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

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

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

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

不检测的最佳工具,但首先要避免这种情况,是使用良好的编程实践。 避免副作用,每次作业只能写一次。 没有任何问题

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

表达式与i = ++ i相同。 能够检测到它的唯一工具就是你的头脑。 在C与权力来负责。

第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’不会改变规则。

这是个好问题。 您突出显示的一件事是“序列点”,引用此站点

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

而且,上面的表达式同样相同,所以行为是未定义的 ,因为跟踪它的工具是零,确定有一个夹板来命名一个作为一个例子,但它是一个C标准,所以可能有一个隐藏在我还没有听说过的工具选项中,也许Gimpel的PC Lint或Riverblade的Visual lint可能对你有所帮助,尽管我承认它没有提及在这方面追踪未定义的行为。

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

它只是表明,代码可能看起来很好,并且编译得很好,但可能会导致后来的麻烦,最好的方法是进行代码审查,可以发现编译器可能无法接收的东西,这是最好的武器选择!