Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 888
kangjianwei Avatar asked Dec 02 '18 05:12

kangjianwei


2 Answers

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; 
like image 159

The Java Language Specification (§15.7) states:

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

The specification (§15.21.1) also states that:

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.

Therefore in Java, the if-statement at runtime would look like the following, which obviously evaluates to false:

if (1 == 2) {  } 

In C, it is simply undefined (see Antti's answer).

like image 25
Jacob G. Avatar answered Oct 02 '22 09:10

Jacob G.