i == (i = 2) 的结果是什么?

What is the result of i == (i = 2)?

运行以下代码:

// In Java, output #####
public static void main(String[] args) {
    int i = 1;

    if(i == (i = 2)) {
        System.out.println("@@@@@");
    } else {
        System.out.println("#####");
    }
}

但是:

// In C, output @@@@@,I did test on Clion(GCC 7.3) and Visual Studio 2017
int main(int argc, char *argv[]) {
    int i = 1;

    if(i == (i = 2)) {
        printf("@@@@@");
    } else {
        printf("#####");
    }

    return 0;
}

问这个问题的动机来自于下面的代码:

// The code is from the JDK 11 - java.util.concurrent.atomic.AtomicInteger
// I am curious about the behavior of the variable prev.
public final int getAndUpdate(IntUnaryOperator updateFunction) {
    int prev = get(), next = 0;
    for (boolean haveNext = false;;) {
        if (!haveNext)
            next = updateFunction.applyAsInt(prev);
        if (weakCompareAndSetVolatile(prev, next))
            return prev;
        haveNext = (prev == (prev = get()));
    }
}

那么,以上两种不同的执行方式如何解释呢?

执行表达式 i == (i = 2) 的 C 程序的 行为未定义.

来自C11 6.5p22:

  1. If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.84)

==左边的i是标量对象i的值计算,右边i = 2有将值 2 分配给 i 的副作用。 == 的 LHS 和 RHS 未排序 w.r.t。彼此。因此整个程序在 C 中是没有意义的。

gcc -Wall编译,GCC会吐出:

unsequenced.c:5:16: warning: operation on ‘i’ may be undefined [-Wsequence-point]
     if(i == (i = 2)) {
             ~~~^~~~

与 C 不同,Java 保证操作数(从左到右)的计算顺序,因此

haveNext = (prev == (prev = get()));

在Java中是正确的。 LHS 的值在评估对 RHS 的副作用发生之前严格确定。

在 C 中,您必须将其写成

newPrev = get();
haveNext = (prev == newPrev);
prev = newPrev;

在 C 语言中,i == (i = 2) 的行为是未定义的,因为它试图在没有中间序列点的情况下更新对象并在计算中使用该对象的值。结果会因编译器、编译器设置甚至周围的代码而异。

Java Language Specification (§15.7) 状态:

The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.

specification (§15.21.1) 还指出:

The value produced by the == operator is true if the value of the left-hand operand is equal to the value of the right-hand operand; otherwise, the result is false.

因此在 Java 中,运行时的 if 语句将如下所示,显然计算结果为 false:

if (1 == 2) {

}

在 C 中,它只是未定义的(参见 )。