44

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?

Sneftel
  • 40,271
  • 12
  • 71
  • 104
kangjianwei
  • 900
  • 9
  • 14
  • 12
    One explains the two different execution modes by first noting that those are two entirely different languages. They happen to share *some* syntax, but that's where the similarities end. – StoryTeller - Unslander Monica Dec 02 '18 at 06:44
  • 4
    The result is : a messy code. Better not imitate this unless you are running for a java obfuscation contest. – Tristan Dec 02 '18 at 07:29
  • 4
    Possible duplicate of [Logic differences in C and Java](https://stackoverflow.com/questions/2028464/logic-differences-in-c-and-java) – user202729 Dec 02 '18 at 08:16
  • (although the specific operator used (==, ++, =, etc.) are different, the answer (it's well defined in Java, sequence point --> undefined behavior) is the same) – user202729 Dec 02 '18 at 08:17
  • 1
    [Undefined behavior and sequence points](https://stackoverflow.com/q/4176328/995714) – phuclv Dec 02 '18 at 16:32
  • Enable compiler warnings, that would have answered your question for you, especially if you'd tried clang. `warning: unsequenced modification and access to 'i' [-Wunsequenced]`. https://godbolt.org/z/UtGRVO – Peter Cordes Dec 02 '18 at 16:44
  • @theg Why should their "motivation" matters? The answers in both posts are idential, no? – user202729 Dec 03 '18 at 05:35
  • 1
    @TheGreatDuck After your edit, the question is still valid and is no longer a duplicate, but **the top voted answer contains a lot of unrelated parts** (and the "two execution mode" statement no longer makes sense). – user202729 Dec 04 '18 at 10:06
  • 1
    @TheGreatDuck Please don't edit the question in a way that changes what the OP is asking, particularly if there are highly-voted answers addressing the original question. If you feel the question is not a valid/good one, closevote/downvote and move on. – Sneftel Dec 04 '18 at 10:19
  • @TheGreatDuck See the revision history. – user202729 Dec 05 '18 at 09:49
  • Btw, is there a reason for not accepting an answer? :D – Antti Haapala -- Слава Україні Dec 17 '18 at 12:57
  • 1
    @AnttiHaapala Just found the "accept" feature... – kangjianwei Dec 17 '18 at 15:04

3 Answers3

60

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;
16

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).

Jacob G.
  • 28,856
  • 5
  • 62
  • 116
5

In C, the behavior of i == (i = 2) is undefined because it attempts to both update an object and use that object’s value in a computation without an intervening sequence point. The result will vary based on the compiler, compiler settings, even the surrounding code.

John Bode
  • 119,563
  • 19
  • 122
  • 198