13

我在项目中使用Coverity Prevent来查找错误。

它报告此表达式的错误(变量名称当然已更改):

x=
   (a>= b) ?
   ++x: 0;

消息是:

EVALUATION_ORDER 缺陷:在“ x=(a>= b) ? ++x: 0;”中,“ x”写在“ x”(赋值 LHS)中并写在“ (a>= b) ? ++x: 0;”中,但副作用发生的顺序未定义,因为没有中间序列点。消息结束

虽然我可以理解 " x = x++" 是未定义的,但这对我来说有点难。这是一个误报吗?

4

6 回答 6

29

条件运算符在条件(第一个操作数)的评估和第二个或第三个操作数的评估之间有一个序列点,但在第二个或第三个操作数的评估之后?:没有专用的序列点。这意味着此示例中的两个修改可能会发生冲突(未由序列点分隔)。所以,Coverity Prevent 是对的。x

您在这方面的陈述实际上等同于

a >= b ? x = ++x : x = 0;

与中相同的问题x = ++x

现在,您的问题的标题似乎表明您不知道是否x = ++x未定义。它确实是未定义的。它是未定义的,原因x = x++与未定义相同。简而言之,如果在一对相邻序列点之间多次修改同一对象,则行为未定义。在这种情况下x,通过赋值进行修改,并且++没有序列点可以将这些修改彼此“隔离”。因此,行为是未定义的。在这方面,++x和之间绝对没有区别。x++

于 2010-09-01T14:53:13.547 回答
12

x= (a>= b) ? x+1: 0;不管消息的准确性如何,用 如果该工具被混淆了,那么下一个查看此代码的人可能也会混淆。

这确实假设x没有您在此处依赖的具有副作用的重载增量运算符。

于 2010-09-01T14:53:16.067 回答
8

该语句在到达序列点之前两次x = ++x;写入变量,因此行为未定义。x

于 2010-09-01T14:53:32.750 回答
3

很难想象编译器会为“x = ++x;”生成代码 这实际上与“++x”不同。但是,如果 x 不是 volatile,编译器处理语句“y = ++x;”是合法的。作为

  y=x+1;
  x=x+1;

语句“x = ++x;” 因此会变成

  x=x+1;
  x=x+1;

如果将一个算术赋值表达式的目标用作另一个的源操作数太快会导致流水线延迟,那么前一种优化可能是合理的。如果递增和分配的变量是相同的,显然是灾难性的。

如果变量“x”是易失性的,我想不出任何代码序列,其中一个不是故意试图变得卑鄙的编译器可以合法地认为“x = x++;” 除了仅读取一次“x”的所有部分并将相同的正确值写入“x”的所有部分两次之外,还有其他任何效果。

于 2010-09-01T16:30:25.577 回答
0

我想从逻辑上讲,如果你写“x=++x”或“x=x++”,无论哪种方式,你都会期望最终结果是 x 比它开始时多一个。但让它只是一个更复杂的阴影。如果你写了 "x=x+(++x)" 怎么办?这和 "x=x+(x+1)" 一样吗?还是我们先加一个,再把x加到自身,即“x=(x+1)+(x+1)”?如果我们写成 "x=(x--)+(x++)" 呢?

即使您可以编写一个语言规范,为这些结构赋予明确的含义,然后可以干净利落地实现它,您为什么要这样做?在对同一个变量的赋值中添加一元增量是没有意义的,即使我们强制理解它,它也没有提供有用的功能。就像,我确信我们可以编写一个编译器,它会接受像“x+1=y-1”这样的表达式并弄清楚这真的意味着“x=y-2”,但是为什么要麻烦呢?没有收获。

即使我们编写的编译器使用“x=x++-++x”做了一些可预测的事情,程序员也必须知道并理解这些规则。如果没有任何明显的好处,它只会无缘无故地增加程序的复杂性。

于 2010-09-01T17:05:55.170 回答
0

为了理解这一点,您需要对序列点有一个基本的了解。请参阅此链接:http ://en.wikipedia.org/wiki/Sequence_point

对于 = 运算符,没有序列点,因此不能保证 x 的值在再次分配给 x 之前会被修改。

于 2012-03-06T05:34:53.207 回答