12

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

那么这段代码怎么样:

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

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

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

4

5 回答 5

12

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

于 2010-08-26T00:47:35.993 回答
4

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

*q += 1;
*p = *q;
于 2010-08-26T05:46:10.423 回答
2

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

于 2010-08-26T00:47:17.503 回答
2

第 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”被间接访问并不会改变规则。

于 2010-08-26T05:40:29.700 回答
1

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

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

更进一步,上面的表达式同样相同,所以行为是undefined,至于追踪它的工具,为零,肯定有夹板以命名一个为例,但它是一个 C 标准,所以也许有一个隐藏我还没有听说过的工具中的选项,也许Gimpel的 PC Lint 或Riverblade的 Visual lint 可能会对您有所帮助,尽管我承认它没有提及在这方面跟踪未定义行为的任​​何内容。

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

它只是表明,该代码在肉眼看来可能看起来不错,并且编译得很好,但以后可能会引起头痛,最好的方法是进行代码审查,以发现编译器可能无法识别的东西,那是最好的武器选择!

于 2010-08-26T00:59:42.713 回答