|
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
|
|
|
|
|
ok... i see it the time of increment is not defined by c++.
i also agree about simplicity. this was a principal question.
The function call example was a good idea.
printf("%d", x++);
But have in mind that x++ returns the current value of x and it is passed to printf. Then we don't care when x will be incremented. We'll always print what we have passed as an argument.
I don't agree that
y = x + x++;
is defined.
As most of you will agree i guess, the compiler reserves the right to evaluate operands and function arguments in any order.
-- modified at 3:13 Friday 16th September, 2005
|
|
|
|
|
pesho2932 wrote:
Then we don't care when x will be incremented
This is the point that I was unfortunately able to make. The exact point at which that increment takes place is unknown and unspecified; only the sequence-point semantics need to be satisfied. This allows compilers to either increment in-place after making a copy or make an incremented copy which does not have to be set until the value is next needed, which by definition is after the sequence point.
"One must learn from the bite of the fire to leave it alone." - Native American Proverb
|
|
|
|
|
pesho2932 wrote:
I don't agree that
y = x + x++;
is defined.
As most of you will agree i guess, the compiler reserves the right to evaluate operands and function arguments in any order.
I suppose this could be true. It could be my fault in believing the writer I quoted in an earlier quote, Tony Gaddis, who said:
"Postfix mode causes the increment to happen after the value of the variable is used in the expression."
If Gaddis is right, then the increment happens after x is used in the expression x + x
But perhaps someone did think it would be funny to mess with this behavior in the compiler to screw us programmers up. I did find a few good quotes on the matter:
Argument is conclusive... but... it does not remove doubt, so that the mind may rest in the sure knowledge of the truth, unless it finds it by the method of experiment. For if any man who never saw fire proved by satisfactory arguments that fire burns. his hearer's mind would never be satisfied, nor would he avoid the fire until he put his hand in it that he might learn by experiment what argument taught.
Bacon, Roger
1214-1294 British Philosopher Scientist
It is not necessary to understand things in order to argue about them.
Beaumarchais, Pierre De
1732-1799 French Dramatist
Men's arguments often prove nothing but their wishes.
Colton, Charles Caleb
1780-1832 British Sportsman Writer
It is better to debate a question without settling it than to settle it without debate.
Joubert, Joseph
1754-1824 French Moralist
If you argue with a woman and win, you lose.
Unknown, Source
That last one doesn't really apply, but I thought it was a good quote.
Danny
-- modified at 9:18 Friday 16th September, 2005
|
|
|
|
|
bugDanny wrote:
"Postfix mode causes the increment to happen after the value of the variable is used in the expression."
This is undoubtfully true. However, I don't see what it has to do with my previous post.
Now I absolutely agree with DavidCrowe and I don't think there is more to be said. I was just unsure wheter "after" in C++ specification means "immediately after" or "sometime after but before the end of the statement"... It looks like the latter one holds.
|
|
|
|
|
pesho2932 wrote:
bugDanny wrote:
"Postfix mode causes the increment to happen after the value of the variable is used in the expression."
This is undoubtfully true. However, I don't see what it has to do with my previous post.
Sorry, I thought you had asked whether the x++ would affect the other x before it was added together to assign to y. If that was what you were asking, then the quote shows that the increment happens after x + x is evaluated. If that wasn't what you were asking, then your question does not matter.
pesho2932 wrote:
Now I absolutely agree with DavidCrowe and I don't think there is more to be said.
Yes, please. But if you mean it, don't refute what someone says, then say you're done talking about it. I agree, this thread has gone on way too long:
An truthful argument will never convince one determined to disagree.
Unknown
Danny
|
|
|
|
|
Whether
y = x + x++;
is defined was not a question. It was an example to compare with x = x++;
Now let me tell you why
y = x + x++;
is NOT defined.
Precedence and associativity of operators lead to this distribution of operands.
y = (x + (x++));
In order to evaluate operator+ the compiler has to have the results from evaluating x and x++. The compiler is free to choose the order of evaluation of these two.
Here are the cases for x = 1.
case 1: x is evaluated before x++
y = 1 + 1 = 2;
case 2: x is avaluated after x++
subcase a:
x++ evaluates to 1
x is incremented
x evaluates to 2
y = 2 + 1 = 3
subcase b:
x++ evaluates to 1
x evaluates to 1
x is incremented
y = 1 + 1 = 2
By the way
"Postfix mode causes the increment to happen after the value of the variable is used in the expression"
means the value is incremented after it is used in x++. Not after all occurances of x in the statement are evaluated.
|
|
|
|
|
You're right, pesho. I was working off of misinformation. You do know that schools and professors lies to us, right? The only thing I disagree with you is:
pesho2932 wrote:
By the way
"Postfix mode causes the increment to happen after the value of the variable is used in the expression"
means the value is incremented after it is used in x++. Not after all occurances of x in the statement are evaluated.
The quote: "Postfix mode causes the increment to happen after the value of the variable is used in the expression" does not mean that it is incremented after it is used in x++, it means it is incremented after x was used in the expression x + x . However, as I admitted in another post on this thread, the author of that book was most likely teaching about the compiler that was distributed with the book, and apparently it does not apply to all C++ code for all compilers.
However, as an aside, after participating in this thread, I believe that the action of x++ or ++x should have been defined in C++, but as an expert explained, it was "too difficult".
Danny
|
|
|
|
|
funny huh...
I believe they would say "Postfix mode causes the increment to happen after the value of the variable is used in the STATEMENT," if they meant what you suggest.
And if you find funny what I say about the order of evaluation of operands, you should revise your knowledge of sequence points.
...as should do anyone who thinks that y = x + x++; is defined by C++.
|
|
|
|
|
No, the writer would no have used the word statement. The full quote I gave in an earlier post read:
"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;
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."
I notice the writer does use the word statement a couple of times in that quote. The writer then goes on to explain how the postfix operator works the same in mathematical expressions. On the next page he writes, "The increment and decrement operators can also be used on variables in mathematical expressions. Consider the following program segment:
a=2;<br />
b=5;<br />
c=a*b++;<br />
cout << a << " " << b << " " << c;
In the statement c = a * b++ , c is assigned the value of a times b , which is 10. b is then incremented. The cout statement will display:
2 6 10 "
But of course this doesn't cover the case where b , for example, is used twice in the same expression. The instruction leads one to believe that in a statement, for example, such as b * b++ , that as in the above b++ would be incremented after used in the expression b * b . This is how it works on my compiler. Apparently that is not so, but you can see where this instruction, and others, would lead one to believe what I had previously assumed.
pesho2932 wrote:
And if you find funny what I say about the order of evaluation of operands, you should revise your knowledge of sequence points.
My, someone's getting touchy. By the way, weren't you the one that asked the question (well, more of a statment really) that started this thread? And now you say you know all about it?
As to your original question. You posted:
int x = 1;<br />
x = x++;
And then stated:
"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."
In your original post the question is trivial. It does not matter when x++ executed, since the increment also reassigns the incremented variable back to itself, as you noted, "But the increment seems to occur after the assignment. And x = 2." So who's the one that should revise their knowledge of C++?"
Danny
|
|
|
|
|
bugDanny wrote:
But of course this doesn't cover the case where b , for example, is used twice in the same expression
Indeed.
As an aside, in the statement cout << num++; there are four expressions: cout << num++ , cout , num , and num++ the first one conicides with the whole statement. So I don't think the writer will refer to it several times as the statement and then use the word expression for the same thing.
Here is a quotation from C++ specification:
"It is important to note that a postfix increment or decrement expression evaluates to the value of the expression prior to application of the respective operator. The increment or decrement operation occurs after the operand is evaluated. This issue arises only when the postfix increment or decrement operation occurs in the context of a larger expression."
I think, here, it is clear what is meant by "the expression."
About x = x++; I was not sure and the question was whether you agree. Now I have a better idea thanks to David Crow ("after" does not mean "immediately after"). About y = x + x++; , I had no question. It is clear to me and I gave it as an example in which the behavior is undefined.
The difference between the two is that in the first case x++ is an operand of operator= so it has to be evaluated before operator= . (But I've come to believe that evaluation of x++ can be considered complete before the increment as there is no sequence point and the result of x++ is independent of the increment. So the increment can occur before the assignment or after.)In the second one x and x++ are the two operands of operator+ so it is not known which one the compiler will choose to evaluate first. (And if it chooses to evaluate x++ first the increment will occur at some later point and may be before or after x is evaluated.)
I'm done with this topic.
|
|
|
|
|
pesho2932 wrote:
So I don't think the writer will refer to it several times as the statement and then use the word expression for the same thing.
Except, of course, in the case where x++ is used in an expression that is not a whole statement, like in, y = c + (b * x++); Here the expression that x is used in before it is incremented is obviously (b * x) .
pesho2932 wrote:
I think, here, it is clear what is meant by "the expression."
Ah, yes, "the expression" being what x++ was called in, not x++ itself, as I had noted. ("the expression prior to application of the respective operator.")
pesho2932 wrote:
I'm done with this topic.
Yes, please let the constant repeating of ourselves be over!
Danny
|
|
|
|
|
So be it.
I have no desire to explain c++ specification to you.
|
|
|
|
|
From the ASM code of VC++2003:
int x = 1;
00412F6E mov dword ptr [x],1
int y;
y = 5 + x++;
00412F75 mov eax,dword ptr [x]
00412F78 add eax,5
00412F7B mov dword ptr [y],eax
00412F7E mov ecx,dword ptr [x]
00412F81 add ecx,1
00412F84 mov dword ptr [x],ecx
printf("y = %d\n", y);
00412F87 mov eax,dword ptr [y]
00412F8A push eax
00412F8B push offset string "y = %d\n" (4240E4h)
00412F90 call @ILT+1320(_printf) (41152Dh)
00412F95 add esp,8
x = 1;
00412F98 mov dword ptr [x],1
x = y + x++;
00412F9F mov eax,dword ptr [y]
00412FA2 add eax,dword ptr [x]
00412FA5 mov dword ptr [x],eax
00412FA8 mov ecx,dword ptr [x]
00412FAB add ecx,1
00412FAE mov dword ptr [x],ecx
printf("x = %d\n", x);
00412FB1 mov eax,dword ptr [x]
00412FB4 push eax
00412FB5 push offset string "x = %d\n" (424054h)
00412FBA call @ILT+1320(_printf) (41152Dh)
00412FBF add esp,8
// Old.
int x = 1;
0041262E mov dword ptr [x],1
x = x;
00412635 mov eax,dword ptr [x]
00412638 mov dword ptr [x],eax
x++;
0041263B mov eax,dword ptr [x]
0041263E add eax,1
00412641 mov dword ptr [x],eax
x = x++;
00412644 mov eax,dword ptr [x]
00412647 mov dword ptr [x],eax
0041264A mov ecx,dword ptr [x]
0041264D add ecx,1
00412650 mov dword ptr [x],ecx
Maxwell Chen
-- modified at 22:50 Sunday 18th September, 2005
|
|
|
|
|