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

kangjianwei :

Run the following code:

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

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

But:

// 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 motivation for asking this question comes from the following code:

// 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()));
    }
}

So, how to explain the above two different execution modes?

Antti Haapala :

The behaviour of a C program that executes the expression i == (i = 2) is undefined.

It comes from 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)

The i on the left-hand side of == is a value computation on the value of scalar object i and the right-hand side i = 2 has a side effect of assigning the value 2 to i. The LHS and RHS of == are unsequenced w.r.t. each other. Hence the entire program is meaningless in C.

Compile with gcc -Wall and GCC will spit out:

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

Unlike C, Java guarantees the evaluation order for operands (left-to-right), therefore

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

is correct in Java. The value of LHS is determined strictly before the evaluation of the side effect on the RHS occurs.

In C you have to write this as something like

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

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=35102&siteId=1