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?
The behaviour of a C program that executes the expression i == (i = 2)
is undefined.
It comes from C11 6.5p22:
- 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;
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 istrue
if the value of the left-hand operand is equal to the value of the right-hand operand; otherwise, the result isfalse
.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With