未排序的修改警告

Unsequenced modification warning

我正在读一本 C 语言的书,但我陷入了这个例子。

作者说这个例子的结果是 x == 0y == 101.

我对 y 结果很好,但是我真的认为表达式中的第一件事会计算 y == y然后将递增 y +1.

我编译了代码并得到了一个警告:未排序的修改并且1被存储在x中。

这是什么原因?

int main(void)
{
    int x,y=100;
    x=y;
    x= y == y++;
    printf ("%d %d",x,y);
    return 0;
}

C 中的一个表达式,包括另一个表达式的子表达式,可能有两种作用:

  • 一个主要作用:它产生一个值以在包含表达式中进一步使用。
  • 副作用:它修改对象或文件或访问易失性对象。

一般来说,C标准并没有说什么时候会出现副作用。 不一定在评价主效应的同时出现

x = y == y++;中,y++有修改y的副作用。但是,y 也用作 == 的左操作数。因为 C 标准没有说明副作用何时会发生,它可能会在使用左操作数 y 的值之前、期间或之后发生。

C 标准中的一条规则指出,如果使用对象的值相对于对该对象的修改没有排序(指定发生在之前或之后),则行为是未定义的。此外,如果两个修改相对于彼此没有排序,则行为未定义。

此规则的最初动机是 y++ 的增量 y 可能需要多个步骤。在只有 16 位运算的计算机中,C 实现可能支持 32 位 int 通过使用多条指令获取 y 的低 16 位,将它们加 1,记住进位,存储结果16位,得到y的高16位,加上进位,存储结果位。如果其他一些代码单独尝试获取 y 的值,它可能会在加 1 之后获取低 16 位,但在进位之前获取高 16 位,结果可能是y 的值既不是添加前的值(例如, 0x1ffff)也不是添加后的值(例如&, 0x20000) 但混合 (0x10000)。你可以说一个实现应该跟踪对象上的操作并将它们分开,这样就不会发生这种交错。但是,这会给编译器带来负担并干扰优化。

在表达式 y == y++ 中,表达式 yy++ 的求值顺序是 未排序的 或者,更简单地说,未指定顺序。

但是,这里的结果取决于表达式的计算顺序。因此,编译器会发出诊断信息。