Pre & post increment operator behavior in C, C++, Java, & C# [duplicate]
Asked Answered
J

6

64

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 |
+-----+-----+------+------+----+
Jer answered 23/6, 2011 at 16:3 Comment(5)
I'm quite certain it is undefined behaviour to increment the same variable multiple times in a statement.Colvin
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.Yolondayon
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.Boito
Do you need an expression like that? Or did you do this experiment because you were curious about it?Alake
No need for such an expression -- just a theoretical question without a rigorous answer.Jer
H
74

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.

Homoeo answered 23/6, 2011 at 16:15 Comment(8)
Exactly, the people saying it's undefined in C# and Java are plain wrong.Wellpreserved
+1 Well -- this sound like a great short answer. Unless it is a hassle, I would appreciate some referencesJer
References or no references, this sums it all up and is the accepted answerJer
@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.Facetious
@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."Doorjamb
@John Thanks a bunch! C behavior was the missing link :)Jer
@Ramus this is great, right on the money!Jer
For C++, it is ISO/IEC 14882:2003(E) §5, ¶4.Chary
S
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.

Stentor answered 23/6, 2011 at 16:14 Comment(6)
Sounds like you're the go-to man when it comes to pre & post increment operators :)Jer
As soon as I my eyes saw "Eric Lippert", my finger clicked on "upvote" :)Homoeo
@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.)Stentor
@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!Panther
You've never used Java? You really should try it sometime; you learn so much about how not to design a programming language...Carpeting
@configurator: We have two former Java language guys on the C# design team, so I think we've got that covered. :-)Stentor
P
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.

Panther answered 23/6, 2011 at 16:6 Comment(6)
I'd say: any answer would be incorrect.Cadency
Its well defined in the other two languages. Just not defined in C++Yolondayon
@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.Panther
@Martin: could you please point to some documentation defining the behaviour in Java and C#? Just curious.Panther
@Vlad: #6457630 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. :-)Yolondayon
@Martin: I've already discovered the answer about C# (see my modified answer). Maybe you could point to the explanation about Java, too?Panther
C
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.

Colvin answered 23/6, 2011 at 16:8 Comment(0)
D
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.

Desberg answered 23/6, 2011 at 16:15 Comment(3)
The Java memory model is concerned with concurrency. I'm pretty sure it does not apply here.Homoeo
That's what I get for typing out of memory. You're right, it's specified elsewhere.Desberg
What does memory model have to do with it? This isn't a question about multithreading.Stentor
M
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.

Microchemistry answered 1/4, 2013 at 12:50 Comment(4)
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).Counterblow
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.Microchemistry
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.Counterblow
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.Counterblow

© 2022 - 2024 — McMap. All rights reserved.