Federico Piazza
Federico Piazza

Reputation: 30985

Why does this expression i+=i++ differs from Java and C?

I know about the prefix and posfix operation... the difference between ++i and i++ and so.

But I think I'm missing something here. Below you can find the code:

package test;

public class Test
{
    public static void main (String[] args)
    {
        int i=0;

        i+=i++;
        System.out.println(i); // Prints 0

        i = i + (i++);
        System.out.println(i); // Prints 0

        i = i + (i+1);
        System.out.println(i); // Prints 1

    }
}

So the output is:

0
0
1

I tried the same code in C:

#include <stdio.h>
#include <string.h>

main()
{
    int i=0;

    i+=i++;

    printf("%d", i);   // prints 1

    i = i + (i++);
    printf("%d", i);   // prints 3

    i = i + (i+1);
    printf("%d", i);   // prints 7
}

and the output was:

1
3
7

Why i+=i++ doesn't increment i while the same code in C it increments the values?

Upvotes: 2

Views: 2298

Answers (8)

Vlad V
Vlad V

Reputation: 1654

Java evaluation order is from left to right and the operands are evaluated before the operation. This means that when i=0 the evaluation is as follows:

i+=i+1
is equivalent to:
i = i + (i++)

evaluating operators from left to right and knowing i=0
i = 0 + (i++)

evaluate i++. it returns 0 and assigns i=1
i = 0 + 0

evaluate 0+0=0
assign i=0, overwriting the previously assigned value of 1

The second expression in your Java code is equivalent to the first one, but the third one is different:

i = i + (i+1)

given that i=0, we evaluate left to right:

evaluate i as 0 and obtain:
i = 0 + (i+1)

evaluate i+1:
    evaluate i as 0 and obtain:
    0+1=1
thus we obtain:
i = 0 + 1
i = 1

Note that (i+1) has no side effects, it only returns the value of i+1 but does not change the value of i.

As for the C code, as far as I know, the execution order in this case is undefined, thus it is up to the compiler implementation to decide. I might be wrong with this one so please correct me.

Upvotes: 0

Eric Lippert
Eric Lippert

Reputation: 660004

Why does this expression i+=i++ differs from Java and C?

i+=i++ is the same as i = i + i++

In Java (and C#) it is required that this be computed left-to-right. That is:

left = i;           // left of +
right = i;          // right of +, original value 
incr = right + 1;   // incremented value
i = incr;           // effect of ++
sum = left + right; // sum of left and right sides of +
i = sum;            // assign sum to i

In C it is possible but not required that this be computed left-to-right. In particular, the assignments

left = i;

and

incr = right + 1;
i = incr;

can be done in the other order. That is, this ordering is legal in C:

right = i;          // right of +, original value 
incr = right + 1;   // incremented value
i = incr;           // effect of ++
left = i;           // left of +
sum = left + right; // sum of left and right sides of +
i = sum;

Which obviously gives a different result. (This is not the only possible reordering, but it is a plausible one.)

So, C and Java are different here because the program fragment isn't well-defined in C to begin with. In Java it is well-defined, it is just bad style.

Upvotes: 7

Patricia Shanahan
Patricia Shanahan

Reputation: 26185

I'm looking at this as a Java question, because it does have a defined result. From time to time I get inspired to analyze one of these questions in terms of the Java Language Specification, especially Chapter 15 - Expressions.

First, i+=i++; with i initially 0.

+= is one of the Compound Assignment Operators. For int i, The statement is equivalent to i = (int)(i+i++);

To evaluate the + we must first evaluate its left hand side, value 0. Next we evaluate its right hand side, i++.

++ is the Postfix Increment Operator. The key statement is "The value of the postfix increment expression is the value of the variable before the new value is stored.", which is 0. The value 1 is stored to i as a side effect, but that does not matter because there will be an assignment to i before it is used again.

Now we evaluate 0+0. + is one of the Additive Operators (+ and -) for Numeric Types. It's a nice simple int addition, result 0.

Finally, we finish the += by doing a cast to int and an assignment as though it were the Simple Assignment Operator =, with no conversion needed because the right hand side type was int. i is now 0.

The second statement is the first one with the += expanded and the int to int conversions dropped. Same result.

The difference for i = i + (i+1); is in the result for a simple addition, +. See, again, Additive Operators (+ and -) for Numeric Types: "The binary + operator performs addition when applied to two operands of numeric type, producing the sum of the operands.". The statement assigns 0+(0+1) to i.

Treating each of the three statements as equivalent to i = i + (i + 1), getting 1, 3, 7, is well within the possibilities for reasonable C implementations.

Upvotes: 0

David Heffernan
David Heffernan

Reputation: 612854

Java

In Java, the expression has a well-defined meaning. The specification for the compound assignment operators says:

A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T)((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.

...

At run time, the expression is evaluated in one of two ways. If the left-hand operand expression is not an array access expression, then four steps are required:

  • First, the left-hand operand is evaluated to produce a variable. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the right-hand operand is not evaluated and no assignment occurs.
  • Otherwise, the value of the left-hand operand is saved and then the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.
  • Otherwise, the saved value of the left-hand variable and the value of the right-hand operand are used to perform the binary operation indicated by the compound assignment operator. If this operation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.
  • Otherwise, the result of the binary operation is converted to the type of the left-hand variable, subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable.

So

i += i++;

is equivalent to

i = i + i++;

Because the value of the left-hand side is saved at the start, and then added to the value of right hand side, and because expression evaluation in Java is left-to-right, the modification of i caused by i++ is overwritten by the subsequent assignment.

All this means that

i += i++;

is equivalent to

i += i;

C

In C the expression

i += i++;

has undefined behavior. And so anything might happen when you execute this code. Which means that you cannot predict what value i will have after the statement completes.

And so it is entirely to be expected that the output from your C program differs from the output from your Java program.

Upvotes: 7

DarkVision
DarkVision

Reputation: 1423

i++ will evaluate the i first so that why you get 0 after the operation finish and stack the value its will increment after.

so if you do this

int i = 0;
System.out.println(i++); = 0
System.out.println(i++); = 1

Upvotes: -1

Hot Licks
Hot Licks

Reputation: 47699

This breaks down into the following internal sequence:

int temp1 = i;
int temp2 = i + i;
i = temp1 + 1;
i = temp2;

(Remember that i++ is post-increment while ++i is pre-increment.)

Upvotes: 1

kviiri
kviiri

Reputation: 3302

i+=i++ is the same as i = i + i++. Let i be zero as in your example.

Now this evaluates as follows:

i = 0 + i++ //evaluate i++ to zero, then increment i by one

i = 0 + 0 //overwrite the value of i with 0 + 0

in other words, you do increment it but immediately overwrite it with the old value.

Upvotes: 5

David R Tribble
David R Tribble

Reputation: 12204

You are using an expression that has undefined behavior.

Specifically, the order of operations on the same operand within the same expression is not well-defined. When you mix in decrement operators, you end up with surprising results, because the compiler is free to rearrange the order that they occur.

Upvotes: 0

Related Questions