|
int x = 1;
x = x++;
I think this should be well defined.
The operations are:
1. ++
2. =
As the expression x++ is an operand of operator=, I think it should be evaluated first (??).
The final value of x should then be 1.
But the increment seems to occur after the assignment. And x = 2.
|
|
|
|
|
pesho2932 wrote:
But the increment seems to occur after the assignment.
x++ is the post-increment operator. it increments after returning the value of the variable.
++x is the pre-increment operator. it increments before returning the value of the variable.
Cleek | Image Toolkits | Thumbnail maker
|
|
|
|
|
I know that (of course).
It can still be after the return and before the assignment. I think it should be there because the expression x++ is evaluated before the assignemet and it's effect should be complete by the time assignment occurs.
|
|
|
|
|
the steps for x = x++; go like this:
1. x++ evaluates to x (1).
1a. the ++ does not happen until after the expression containing it is complete (roughly speaking)
2. assign the value from step 1 to x (x=1)
3. x++ is performed, which increases x (2)
Cleek | Image Toolkits | Thumbnail maker
|
|
|
|
|
pesho2932 wrote:
As the expression x++ is an operand of operator=, I think it should be evaluated first (??).
Wrong. The ++ operator will complete before anything is assigned. Why would you want a half-baked value to be assigned to x ?
pesho2932 wrote:
The final value of x should then be 1.
It should be 2 as the current value of x , which is 1, is incremented by one, and the result of 2 is then assigned to x .
pesho2932 wrote:
But the increment seems to occur after the assignment. And x = 2.
Correct.
"One must learn from the bite of the fire to leave it alone." - Native American Proverb
|
|
|
|
|
DavidCrow wrote:
pesho2932 wrote:
As the expression x++ is an operand of operator=, I think it should be evaluated first (??).
Wrong. The ++ operator will complete before anything is assigned. Why would you want a half-baked value to be assigned to x?
Hmm, being a postfix, the ++operator will complete at the end of the expression, so x = x will complete first, and then x with be incremented with ++. But maybe you explain it later in your response.
DavidCrow wrote:
pesho2932 wrote:
But the increment seems to occur after the assignment. And x = 2.
Correct.
Wait, if this is correct, and the increment occurs after the assignment, then how was you earlier statement correct, where you say the ++ operator will complete before anything is assigned? Your statements are in conflict.
In any case, this question is a moot point. We are dealing with one variable. The assignment is unnecessary, since x++ is the same as x += 1 and x++ will increment x, without having to reassign to x. Whether you increment before or after the assignment x = x does not matter. Then end result will be x == 2. Of course, while writing code compactly in one line might be cool and impressive, it is a lot easier to read if you separate the assignment and increment. Such as:
x = x;<br />
x++;
or...
x++;<br />
x=x;
In this way, someone reading your code is able to see much easier what you meant by that line of code and it makes finding and correcting errors much easier.
Danny
|
|
|
|
|
bugDanny wrote:
Hmm, being a postfix, the ++operator will complete at the end of the expression, so x = x will complete first, and then x with be incremented with ++. But maybe you explain it later in your response.
There are actually two expressions here. For VS6, the inner one (x++) is evaluated first and then the outer one (x=). The Precedence and Order of Evaluation rules dictate that postfix is always evaluated before assignment. For that matter, assignment is always evaluated last (with one exception).
Another way to look at this is the way some folks (used to) combine assignment and comparison statements into one, like:
while ((str = fgets()) != NULL)
... In this example, the inner, parenthesized expression (str = fgets() ) is evaluated first, and then the outer expression (str != NULL ) is evaluated last. It wouldn't make much sense to compare str to NULL before it had been assigned a value from the inner expression.
bugDanny wrote:
Wait, if this is correct, and the increment occurs after the assignment, then how was you earlier statement correct, where you say the ++ operator will complete before anything is assigned? Your statements are in conflict.
My bad. I meant to reiterate that the ++ operator was being evaluated before the assignment. Sorry for the confusion.
"One must learn from the bite of the fire to leave it alone." - Native American Proverb
-- modified at 14:12 Thursday 15th September, 2005
|
|
|
|
|
x++ is a postfix operator, evaluating after the other expression evaluates. Try these experiments...
int x = 1;<br />
cout << x++;
If ++ behaved as you explained, then x++ should have incremented x before displaying, and the output would be 2. My experiment yields the output to be 1, since x is incremented after the other expression.
But wait, we were talking about assignments, not the use of (<<). So try this...
int x = 1;<br />
int y;<br />
y = x++;<br />
cout << y;
What is displayed now. The experiment is the same as in x = x++ , only now the assignment is stored in a different variable. It is no longer trivial.
DavidCrow wrote:
The inner one (x++) is evaluated first and then the outer one (x=). The Precedence and Order of Evaluation rules dictate that postfix is always evaluated before assignment.
According to this, x++ should be evaluated before y= . My experiment yields otherwise. Does The Precedence and Order of Evaluation perhaps talk about C, or an earlier version of C++?
Danny
|
|
|
|
|
bugDanny wrote:
But wait, we were talking about assignments...
Exactly. My earlier staments were about the postfix and assignment operators. They don't necessarily hold true for cout and the << operator.
bugDanny wrote:
cout << y;
What is displayed now.
Exactly what you told it to display, the value in y .
bugDanny wrote:
It is no longer trivial.
Trivial or otherwise, using the postfix and assignment operators in this fashion is a sure recipe for disaster. I've never done it this way, and can't see myself doing it in the future. I'm not a big fan of bad programming practices. That's all I can offer.
"One must learn from the bite of the fire to leave it alone." - Native American Proverb
|
|
|
|
|
DavidCrow wrote:
bugDanny wrote:
cout << y;
What is displayed now.
Exactly what you told it to display, the value in y.
And the value in y was y = x++ , and should have been 2, if, as you said, x++ incremented before assigning to y. It was not 2, but 1, showing that the postfix operator incremented after the assignment.
DavidCrow wrote:
Trivial or otherwise, using the postfix and assignment operators in this fashion is a sure recipe for disaster. I've never done it this way, and can't see myself doing it in the future.
I agree with you wholeheartedly, as I mentioned in one of my responses earlier. But the question was not should he do it, he asked what would happen if he did it.
Danny
|
|
|
|
|
too add to the confusion.
8: int x = 1;
00401788 mov dword ptr [ebp-4],1
9: int y = 2;
0040178F mov dword ptr [ebp-8],2
10: int z = 0;
00401796 mov dword ptr [ebp-0Ch],0
11: z = y++, y = x++ ;
0040179D mov eax,dword ptr [ebp-8] #Set eax = to the value of X = 1
004017A0 mov dword ptr [ebp-0Ch],eax #Set Y = EAX = 1
004017A3 mov ecx,dword ptr [ebp-8] #Move vlaue of X to ECX
004017A6 add ecx,1 #Add 1 to ECX
004017A9 mov dword ptr [ebp-8],ecx #Move NewValue to Y = 2
004017AC mov edx,dword ptr [ebp-4] #Move X to EDX = 1
004017AF mov dword ptr [ebp-8],edx #Move EDX to Y = 1
004017B2 mov eax,dword ptr [ebp-4] #Move X to EAX
004017B5 add eax,1 #increment
004017B8 mov dword ptr [ebp-4],eax #finaly Reset the value of X
out put Z=2 Y=1 X=2
The increment always happens last.
When used in an expression the compiler takes the value and sticks it in assembly after the rest of the statement has been compiled it does the increment.
a programmer traped in a thugs body
|
|
|
|
|
bugDanny wrote:
But the question was not should he do it, he asked what would happen if he did it.
Agreed. To quote K&R from many years ago:
"The moral is that writing code that depends on order of evaluation is a bad programming practice in any language. Naturally, it is necessary to know what things to avoid, but if you don't know how they are done on various machines, you won't be tempted to take advantage of a particular implementation."
"One must learn from the bite of the fire to leave it alone." - Native American Proverb
|
|
|
|
|
DavidCrow wrote:
"The moral is that writing code that depends on order of evaluation is a bad programming practice in any language. Naturally, it is necessary to know what things to avoid."
Well said!
Danny
|
|
|
|
|
See this comp.lang.c faq[^] explaining why this is undefined behavior. Curiously enough, in C++ the expression works as you expect if you use some user defined type rather than a built-in integer:
class Integer
{
public:
Integer(int i)...
Integer operator++(int)...
...
};
Integer x=1;
x=x++; because for user defined types, x++ is really a function call and so establishes a so-called sequence point --but this is not the case for built-in types. HTH.
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
Want a Boost forum in Code Project? Vote here[^]!
-- modified at 12:54 Thursday 15th September, 2005
|
|
|
|
|
Munoz's reply may or may not be correct, I don't know, but his response applies to the C Programming, not to C++. If you follow his link, then click on a link to top somewhere near the bottom of the page, you will see this line under "comp.lang.c Frequently Asked Questions":
This collection of hypertext pages is Copyright 1995 by Steve Summit. Content from the book "C Programming FAQs: Frequently Asked Questions"...
The explanation was made for C. I don't know as much about C as I do about C++. I know they're similar, but they are NOT the same. Notice this line from a C++ book ("Standard Version of Starting Out with C++" by Tony Gaddis):
"The difference is important, however, when these operators are used in statements that do more than just incrementing or decrementing. For example, look at the following lines:
num = 4;<br />
cout << num++;
The cout statement above is doing two things: (1) displaying the value of the num, and (2) incrementing the num. But which happens first? cout will display a different value if num is incremented first than if num is incremented last. The answer depends upon the mode of the increment operator.
Postfix mode causes the increment to happen after the value of the variable is used in the expression. In the statement above, cout will display 4 and then num will be incremented to 5." (italics mine).
Danny
-- modified at 8:52 Friday 16th September, 2005
|
|
|
|
|
Munoz's reply may or may not be correct, I don't know, but his response applies to the C Programming, not to C++.
In this aspect, C++ behaves exactly as C. If you want to consult the exact reference, check the standard for the definition of sequence points (here's a link[^] to a draft version of the standard at the relevant section, check item -4-; sequence points are defined here[^],all thru 1.9.)
Your cited example
cout<<num++; is well defined because num is modified only once on the expression. A little more contrived example
cout<<num++<<num++; is also well defined, as this expression is equivalent to
ostream::operator<<(ostream::operator<<(cout,num++),num++); which has an intervening sequence point between both numm++ calls (the innermost function call to ostream::operator<< is such sequence point.) But the expression
x=x++; is undefined behavior since there's no intervening sequence point: neither the postfix increment to an int nor the assignment to an int are function calls; so, here applies the restriction on modification of scalar values linked to above.
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
Want a Boost forum in Code Project? Vote here[^]!
|
|
|
|
|
Did you read the rest of this thread? Notice my other posted message that read,
Tony Gaddis said:
"Postfix mode causes the increment to happen after the value of the variable is used in the expression." (Italics mine)
So the increment happens after x is assigned to x, which really doesn't matter since the increment then assigns x++ back to x.
However, notice also one of my previous comments in this thread. x=x++ is just like x.operator=(x++); Being a postfix, and noting the explanation Gaddis gives above, the original value of x should always be used in the expression first, such as in x=x, then x is incremented.
Just to rehash some other posts in this thread.
Danny
|
|
|
|
|
However, notice also one of my previous comments in this thread. x=x++ is just like x.operator=(x++); ...
That's the flaw in your argument: if x is an int , x=x++ is not like x.operator=(x++) . There's no such a thing as int::operator=() or anything similar, try to compile that if you don't believe me. Your argument holds, as I say in my first post, if you're using an user defined type, but in the case of scalar values the sad fact is that the expression x=x++ is undefined behavior.
If the exposition on the standard and my explanations do not convince you, please let me forward you to this answer[^] to the very same problem by Andrew Koenig. Andrew is one of the original designers of the C++ language along with Bjarne Stroustrup, so I think you'll be willing to trust his opinion on this matter.
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
Want a Boost forum in Code Project? Vote here[^]!
|
|
|
|
|
Joaquín M López Muñoz wrote:
There's no such a thing as int::operator=() or anything similar
I know this. I was trying to use it as an example of what is happening.
Joaquín M López Muñoz wrote:
please let me forward you to this answer[^] to the very same problem by Andrew Koenig
Thank you for this. I was wondering about a non-trivial situation where someone might write x=x++ .
Joaquín M López Muñoz wrote:
Andrew is one of the original designers of the C++ language along with Bjarne Stroustrup, so I think you'll be willing to trust his opinion on this matter
I appreciate the information you provided. As I admitted in one of my other posts, the author I was quoting could have been just plain wrong, or perhaps he was writing the book just in conjuction with the compiler he was distributing the book.
So I guess the whole point of this thread may be: Don't sit and theorize about how the code should or shouldn't work, or what may or may not happen when you compile it. Compile the code, test it, and then you will know just how it works. But even better: simplify your code, remove ambiguity, and don't leave problems such as this up to the compiler to try to figure out.
Danny
-- modified at 13:41 Friday 16th September, 2005
|
|
|
|
|
It's me pesho. I've seen:
1. my question has not been understood
2. many people don't have a clear idea of c++
so now let me explain better...
imagine the following
y = x + x++;
this is UNDEFINED for sure. precedence & associativity tell u how to group operands ---
y = ((x) + (x++))
but u don't know whether (x) or (x++) will be evaluated first.
i hope that's clear to all.
now see how my question differs from this case.
x = x++;
in this case x++ must be evaluated before it is passed as an argument to the assignment operator.
so i thought the side effect of x++ (incrementing x) must also be complete before the assignment takes place. But maybe it is not so. Maybe because u know the result of x++ without having to increment u can postpone it for the end of the whole statement for example.
a similar example which is defined for sure is"
x = 1;
something = x++ && x;
this is equal to
something = 1 && 2;
because && is a sequence point.
|
|
|
|
|
as i though about it.. my most likely hypothesis is that c++ does not define when exactly the increment will occur... it just says that it will be somewhere after the evaluation of the result...
so all this is bullshit..
can someone confirm this?
|
|
|
|
|
Anonymous wrote:
x = x++;
in this case x++ must be evaluated before it is passed as an argument to the assignment operator.
so i thought the side effect of x++ (incrementing x) must also be complete before the assignment takes place. But maybe it is not so.
It is not so. First, the x part of x++ is passed to the operator=() function, then x++ increments x. When x++ increments x, the incremented number is at the same time reassigned to x. Try,
printf("%d", x++);
This might show it better, since now it is clearly seen that x++ is being passed to printf. That line will print the original value of x, then increment x.
Anonymous wrote:
Maybe because u know the result of x++ without having to increment u can postpone it for the end of the whole statement for example.
This is sort of correct. You don't know the result of x++ yet. First, x is passed into the other expression in the line, then x is incremented. Take your example:
Anonymous wrote:
y = ((x) + (x++))
This line is made up of 3 expressions: y=, x++, and x + x++. The = expression has to wait until an expression is ran in order to pass something to y=. So you say,
Anonymous wrote:
but u don't know whether (x) or (x++) will be evaluated first.
But you do know. Let's rewrite the line using functions instead of operators. This line would be:
y.operator=(x.operator+(x++));
We know C++ works from the inside out. y.operator=() is called, but that needs to evaluate x.operator+(x++)) before it can execute, so x.oeprator+() is called, but that needs to evaluate x++ before it can execute. So first x++ is examined and passed to x.operator+() . This means that the original x is passed to the function before it is incremented, since we are using the postfix of ++. The x.operator+() was called with the original x; it was called before x was incremented.
So x is passed to x.operator+() , so we have x + x , then x is incremented, which doesn't affect the original y.operator=() since the expression x + x was passed to that.
As I have pointed out in other responses, we should avoid confusion in our code. Here is that same line of code written out to avoid confusion. This is how that line works:
int x = somevalue;<br />
int y;<br />
int temporaryValue = x + x;<br />
x++;<br />
y = temporaryValue;
Hope this unconfuses anything.
Danny
|
|
|
|
|
Anonymous wrote:
my question has not been understood
i read this whole post and didn't see a single question mark. what's your question ?
yes, the post-increment operator can generate code that leads to undefined compiler behavior - that's well-known and well understood. but, in those cases, the code can generally be re-written in a way that avoids the situation. simply chopping the complex operation into sub-operations will eliminate the ambiguity from the compiler's point of view, as well as making life easier for any unfortunate maintenance programmer who has to look at your code in the future.
Cleek | Image Toolkits | Thumbnail maker
|
|
|
|
|
Chris Losinger wrote:
i read this whole post and didn't see a single question mark
You're right, sort of. There's a question mark in the subject line.
Chris Losinger wrote:
the post-increment operator can generate code that leads to undefined compiler behavior
The post-increment operator actually works just like it's supposed to. We, as humans, however, don't seem to understand as well, so we call it 'undefined'.
Chris Losinger wrote:
the code can generally be re-written in a way that avoids the situation
This is absolutely correct. Our code should always strive for simplicity, even if it makes the code long or unelegant.
Danny
|
|
|
|
|
bugDanny wrote:
The post-increment operator actually works just like it's supposed to. We, as humans, however, don't seem to understand as well, so we call it 'undefined'.
In and of itself, yes, but when combined with other expressions, we can't say for sure which order the compiler will evaluate the various dependent parts in. That's the part that is undefined.
bugDanny wrote:
Our code should always strive for simplicity...
Agreed. Because the compiler happens to evaluate an expression in the order a programmer wanted, the programmer assumes that since it works it must be okay.
"One must learn from the bite of the fire to leave it alone." - Native American Proverb
|
|
|
|
|