2

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?

Federico Piazza
  • 30,085
  • 15
  • 87
  • 123
  • 5
    Pick a tag: C or Java. That will determine whether this gets 100 upvotes or downvoted into oblivion. – Mysticial May 08 '14 at 22:03
  • 1
    Post your c too. The Java seems correct – exussum May 08 '14 at 22:03
  • For C this would be a duplicate of http://stackoverflow.com/questions/9060747/sequence-points-and-order-of-evaluation. It strongly smells like Java, though. – Jongware May 08 '14 at 22:05
  • Find a page about your language of choice's operators and their precedence; then compute the result! – fge May 08 '14 at 22:07
  • For java, possible duplicate of http://stackoverflow.com/questions/11570589/java-i-operation-explanation and/or http://stackoverflow.com/questions/7911776/what-is-x-after-x-x – tcollart May 08 '14 at 22:07
  • @fge I think the question is - why is the result different, between the two languages. – Dawood ibn Kareem May 08 '14 at 22:07
  • There is a similar C# post that took a lot of attention http://stackoverflow.com/questions/13516689/for-i-0-why-is-i-i-equal-to-0 – Kostas Kryptos May 08 '14 at 22:08
  • @DavidWallace well yes, and the precedence of operators may differ from one language to the other -- if it is defined at all for C which is pretty liberal. For Java it is defined by the JLS so no problem there – fge May 08 '14 at 22:09
  • @fge - and _that_ is the answer. – Dawood ibn Kareem May 08 '14 at 22:10
  • @Mysticial didn't understand the downvote sorry to not be a center of wisdom like you... it just called my attention – Federico Piazza May 08 '14 at 22:10
  • Precedence of operators only refers to parsing and is the same here. But semantics differ. In C it's undefined because of 2 unsynchronized accesses, in Java it's okay. – zch May 08 '14 at 22:11
  • 3
    @Fede I didn't downvote. I was just poking fun at the fact that questions like this in Java tend to get hundreds of upvotes whereas the same question in C or C++ would get downvoted to -10, closed as stupid, and then deleted. – Mysticial May 08 '14 at 22:12
  • @Mysticial: In C or C++ it would probably just get closed as a duplicate of one of many, many identical questions, and everyone would move on. – Kerrek SB May 08 '14 at 22:20
  • @Mysticial ok, no worries. I was wonder of why I had different outputs for the same code. It wasn't obvious for me. People answers and comments helped me to be clear about it. I don't use to ask these kind of questions as you can see on my profile. Still don't understand why downvotes, it is only a questions and don't consider it so bad... seems there are many smart and intolerant people here – Federico Piazza May 08 '14 at 22:30
  • @Fede It's not a bad question (actually, it's a good question for first-timers). It's just that it's such a commonly asked question that the C and C++ folks have completely lost their patience and will destroy them on sight. I don't know how the Java community is able to handle it so differently. – Mysticial May 08 '14 at 22:33
  • Dupe: [why-x-x-gives-different-results-for-c-and-java?](http://stackoverflow.com/questions/17144359/why-x-x-gives-different-results-for-c-and-java?lq=1) – nawfal Jul 20 '14 at 07:34

8 Answers8

7

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.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
7

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.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    @Fede: You're welcome. You might also want to carefully read http://stackoverflow.com/questions/3346450/what-is-the-difference-between-i-and-i/3346729#3346729 -- the question is about C# but applies pretty well to Java. – Eric Lippert May 08 '14 at 22:53
5

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.

kviiri
  • 3,282
  • 1
  • 21
  • 30
  • thanks kviiri, so how C evaluates this, I expected java resolves it in the same way – Federico Piazza May 08 '14 at 22:11
  • 4
    @Fede, I know my Java far better than I do my C, but I believe this is undefined behavior. In other words, you may get different results different times when you run the program, or when using a different compiler. – kviiri May 08 '14 at 22:13
1

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

999k
  • 6,257
  • 2
  • 29
  • 32
Hot Licks
  • 47,103
  • 17
  • 93
  • 151
0

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.

David R Tribble
  • 11,918
  • 5
  • 42
  • 52
0

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.

Vlad V
  • 1,594
  • 1
  • 13
  • 28
  • 1
    Saying that the operators are evaluated before the operands is confusing; clearly if you add x + y then the operands -- x and y -- must be evaluated before the result of operator + is evaluated. Are you sure that's what you meant to say? – Eric Lippert May 08 '14 at 22:47
  • But if we have, for example, a + b + c, we could evaluate a, b and then a + b and then evaluate c and add it to the result. – Vlad V May 09 '14 at 09:24
  • 1
    Correct. Let's instead say `a * b + c`. The `+` has two operands: `a*b` and `c`. The *operands* of `+` are both evaluated *before* the `+`. The `*` has two operands: `a` and `b`. Again, the operands are evaluated *before* the operator. Now, there is no requirement that the operand `c` of the `+` be evaluated before the `*`, but the `c` isn't even an operand of the `*`, so that's not relevant. – Eric Lippert May 09 '14 at 13:23
  • Right. Now I see it, I'm sorry. I meant *operands are evaluated before operators*. I edited my post, thank you. – Vlad V May 09 '14 at 15:37
0

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.

Patricia Shanahan
  • 25,849
  • 4
  • 38
  • 75
-1

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
DarkVision
  • 1,373
  • 3
  • 20
  • 33
  • That is not what OP is asking. Also from "*I know about the prefix and posfix operation*" we can assume that OP knows main idea behind `i++`. Question is why code in Java returns `0,0,1` while same code in C `1,3,7`. – Pshemo May 08 '14 at 22:15
  • i don't think its wrong or bad answer logically that how java and C# work but in C the order of evaluation of subexpressions is unspecified so yeah he might understand the prefix and postfix but he should verify if the behavior is the same. – DarkVision May 08 '14 at 22:23
  • I am not saying your answer is untrue. I am saying that as it stays now it doesn't answer OP question because it doesn't say anything about undefined behaviour in C. – Pshemo May 08 '14 at 22:33
  • didn't downvote but I think it's because you put same i++ expressions while the 2nd one should be ++i – Federico Piazza May 08 '14 at 22:45
  • no worrie jsut a downvote but if you try System.out both like that it will output 0 and 1 you don't need to ++i on the second one – DarkVision May 08 '14 at 23:17