65

DISCLAIMER: This is not a real-world example. It is just a theoretical question of how these languages work.

What exactly are the differences between C/C++, C#, and Java when it comes to post & pre increment operators?

This is what I get with VC++10, Java 1.6, and C# 4

int a = 2;
int b = a++ + a++;
int c = ++a + a++ + a++;

      +-----+------+------+----+
      |  C  | C++  | Java | C# |
+-----+-----+------+------+----+
| a   |  7  |  7   |   7  |  7 |
+-----+-----+------+------+----+
| b   |  4  |  4   |   5  | 5  |
+-----+-----+------+------+----+
| c   | 15  |  15  |  16  | 16 |
+-----+-----+------+------+----+
5
  • 3
    I'm quite certain it is undefined behaviour to increment the same variable multiple times in a statement. Commented Jun 23, 2011 at 16:06
  • 6
    Its well defined in the other two languages. Just not defined in C++. Do you really see ANY code in real life that looks like that? If you can not work out in your head what the answer should be for a given value of a (without running it in the compiler) then you should not write it. Commented Jun 23, 2011 at 16:10
  • 11
    Programming is hard enough as it is without making life this hard for yourself. Why on earth would you want to write expressions like that? For the love of god, get rid of the belief that code is better if it all fits on a single line and uses as few characters as possible. Commented Jun 23, 2011 at 16:11
  • Do you need an expression like that? Or did you do this experiment because you were curious about it? Commented Jun 23, 2011 at 16:12
  • 14
    No need for such an expression -- just a theoretical question without a rigorous answer. Commented Jun 23, 2011 at 16:13

6 Answers 6

75

Java and C# evaluate expressions from left to right, and the side-effects are visible immediately.

In C++, the order of evaluation of subexpressions is unspecified, and modifying the same object twice without an intervening sequence point is undefined behavior.

Sign up to request clarification or add additional context in comments.

8 Comments

Exactly, the people saying it's undefined in C# and Java are plain wrong.
+1 Well -- this sound like a great short answer. Unless it is a hassle, I would appreciate some references
@Nick: For C, see N1256 (PDF), sect 6.5, para 2; sect 6.5.2.4, para 2. I can't get to the C++ standard currently, but the language is largely the same.
@Nick: Java specifies this in JLS §15.7 "Evaluation Order": "The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right."
For C++, it is ISO/IEC 14882:2003(E) §5, ¶4.
|
33

I don't have the time to write up a detailed description of the differences between C++, C, C# and Java. I will merely say that the C# behaviour of the pre and post increment operators is fully specified (in single-threaded scenarios; if you want to know about its atomicity, guarantees about observations of read and write orders in multi-processor weak memory models and so on, you're on your own to do that research.) It is not fully specified in C and C++; a compiler has broad lattitude to do whatever it pleases with re-ordering side effects. I have never used Java so I'm not going to hazard a guess as to what Java does.

For more information on what C# does you should read the C# specification. For a short take on it, read my answer to this question:

What is the difference between i++ and ++i?

For an even shorter take:

Subexpressions in a C# expression are logically grouped by precedence and associativity, and then evaluated from left to right regardless. (So for example, A() + B() * C() evaluates A(), then B(), then C(). The fact that the multiplication "comes before" the addition is irrelevant; the subexpressions are always evaluated left to right.)

If the evaluation of a subexpression causes a side effect because of a pre or post increment subexpression then the side effect happens immediately before the result is produced.

6 Comments

Sounds like you're the go-to man when it comes to pre & post increment operators :)
As soon as I my eyes saw "Eric Lippert", my finger clicked on "upvote" :)
@Vlad: subexpressions are evaluated left to right, period, end of story. (Full disclosure: C# 4 has some bizarre bugs where sometimes we accidentally evaluate subexpressions in the wrong order when the named-and-optional-parameter call analyzer gets confused; those bugs will be fixed in later releases.)
@Eric: Actually, I removed my question, because the grouping would logically not affect anyway the evaluation order, so the question doesn't make sense. In any case, thanks for the answer!
@configurator: We have two former Java language guys on the C# design team, so I think we've got that covered. :-)
|
4

In C++, this is undefined behaviour, so any answer would be correct. See Undefined behavior and sequence points for further details.

Not sure about other languages, but I would expect this code to be incorrect there, too.

EDIT:
See Eric Lippert's answer about C#. He disproves my assumption about C#'s behaviour.

6 Comments

I'd say: any answer would be incorrect.
Its well defined in the other two languages. Just not defined in C++
@Kirill: as I understand this, the undefined behaviour means that anything the program does is correct (including formatting the hard disk and launching nasal demons), from the compiler point of view. The fact that such a behaviour is usually not what the code author expects is a completely unrelated issue and not compiler's fault.
@Martin: could you please point to some documentation defining the behaviour in Java and C#? Just curious.
@Vlad: stackoverflow.com/questions/6457130/… I could be wrong about Java. But both languages designers saw all the silly question from C++ noob and said lets not get distracted by stupid questions and just define the behavior. :-)
|
4

In C++ at least this undefined behaviour. Quoting the C++ standard:

Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression.

Comments

1

The Java memory model ensures the order the loads and stores are done, so it should come out the same on any JVM (I believe).

It looks like C++ has the same order of operations, but once you use it twice on a line you start running into other stuff (Vlad is right there). If you try other C++ compilers, you may find they come up with different answers.

I'm sure C# has the same order of operations, but my guess is they have a memory model (like Java) that ensures consistency, but I don't have a lot of knowledge here.

3 Comments

The Java memory model is concerned with concurrency. I'm pretty sure it does not apply here.
That's what I get for typing out of memory. You're right, it's specified elsewhere.
What does memory model have to do with it? This isn't a question about multithreading.
1

I like this question and found very good explanations but I just want to explain this question by it's value how it is evaluated:

I will only talk about java and c/C++ as I have no knoledge about C#

Statements are evaluated in following ways

In java

Statement ||||||||||||||||||||||||||||||||||||||||||||||||||||||| Trace

int a= 2;                     a=2
int b= a++ + a++;             a=2, a=3

here value of a=4

int c = ++a + a++ + a++;      a=5, a=5, a=6

here value of a=7

In C/C++

Statement Trace

int a= 2;                     a=2
int b= a++ + a++;             a=2, a=2

here value of a=4

int c = ++a + a++ + a++;      a=5, a=5, a=5

here value of a=7

In short in java expression goes left to right so at the 2nd "a" it will fetch new value and in c/c++ it will first evaluate whole expression and then increment all operands of statement.

4 Comments

int b= a++ + a++; is undefined behaviour in C and C++, since a is modified twice without intervening sequence point (ditto for the int c = ... thing).
Yes you are right, I had also read that but I am just confuse and want to know how its behavior is undefined? Because in C/C++ if you also evaluate int a=2; and int b = a++ + a++ + a++ + a++; b's output will be same 8, it will take value and then do post increment of that operand after finishing of that statement. I hope you will get what I am trying to say.
Undefined means there's no restriction on what happens by the standard. It would not violate the standard if the compiler inserted an abort() call for the undefined behaviour. But of course no serious implementation does such things. Variations closer to the code include different orders of evaluation (right-to-left, middle-to-outer, invent-your-own) and the question of when the incremented value is stored, whether a is read only once or several times. So it would be legal for the value of a to be read three times, and the incremented value of a stored after evaluating the expression.
That could lead to int c = ++a + a++ + a++; being evaluated as 5 + 4 + 4, and then three times storing 4+1 into a, thus c == 13 and a == 5 afterward. Or the middle term evaluated first, and the incremented value not stored yet, then the ++a with immediate storing of the incremented value, then the right a++ with a new reading of the value, leading to c = 5 + 4 + 5 and a could be 5 or 6, depending on which pending store from the two a++ is done last.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.