• Advertisement
Sign in to follow this  

preincrement and assignment

This topic is 3228 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Let's talk about this snippet of code:
int i = 0;
i = ++i;
Observations (please correct me if I'm wrong): 1. Since we are writing to i twice without a sequence point in between, the behavior is undefined. So the following discussion is just for amusement. 2. We don't know wether the left operand or the right operand of the assignment is evaluated first. 3. If the right operand is evaluated first, this means that the VALUE of the expression "++i" is 1, but that does not imply that the value of i is 1 at that point, because we don't know exactly when ++ takes EFFECT. 4. If we further assume that the side effect of assignment happens before the side effect of increment, we get 2 as a value of i at the semicolon. Nobody I have discussed this issue with seems to agree with me on point 4. Share your thoughts :)

Share this post


Link to post
Share on other sites
Advertisement
No matter how you look at it I'm not sure how you can get a i == 2 after doing a ++ on a i of 0...
Unless you mean it assigns a ++'ed i to i then does the ++ on the already assigned i, but it's hardly logical

Share this post


Link to post
Share on other sites
Quote:
Original post by Rewdew
but it's hardly logical

But is it... plausible?

Share this post


Link to post
Share on other sites
the ++ operator when placed before the variable does not return a value unless the variable itself has been increased by one. So I dont think saying the expression's value is anything if it isnt already evaluated, and by that point the registers already have the pointer to i waiting for the right side of the assignment to be caclulated.

im not sure if that answered the question/statement, maybe I missed something lol

Share this post


Link to post
Share on other sites
++i is evaluated first and returns a reference to itself which it is assigned to...?

i dont see what the problem is?

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
But is it... plausible?

Not really no

Share this post


Link to post
Share on other sites
According to the standard, this is undefined, as you have pointed out correctly.

However, other than with the similar example of post-increment, I think that the result is nevertheless well-defined here, since the compiler really has no other choice but to evaluate ++i first.
If it was decided to do the assignment first, it would still have to evaluate the increment before that, as it needs the value to assign, which it can't get without evaluating the pre-increment first.

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
4. If we further assume that the side effect of assignment happens before the side effect of increment, we get 2 as a value of i at the semicolon.

Nobody I have discussed this issue with seems to agree with me on point 4. Share your thoughts :)

Using your code as a starting point and producing this sample program:

int main(int, char **) {
int i = 0;
i = ++i;
std::cout << i;
return 0;
}

MSVC 2008 spits out 1 for the value of i. So given the fact that a compiler has disagreed with your logic, I think you're going to have to live with the fact that 4 doesn't hold true.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
So given the fact that a compiler has disagreed with your logic, I think you're going to have to live with the fact that 4 doesn't hold true.

So the output of one compiler defines undefined behavior? Hmmm... :)

Share this post


Link to post
Share on other sites
No, the existence of one counterexample is enough to prove a statement false.

Share this post


Link to post
Share on other sites
I simply stated one possible scenario of undefined behavior -- there are others, like the one you encountered. If I write

"hello"[1] = 'a';

and the computer does not crash, this doesn't mean that's what always happens.

Share this post


Link to post
Share on other sites
I'm not saying that it's always 1. I am saying that since it was 1 at least once, then saying that it should be 2 is wrong.

Share this post


Link to post
Share on other sites
Ignoring the fact that undefined behaviour means you could get any answer...
How could you expect it to be possible to get two when that would mean incrementing the value of i when it equals 1, but to get to one to begin with means i was incremented already, thus it involves two increments?

Share this post


Link to post
Share on other sites
You cannot get 2, and here's why, despite the lack of a sequence point.

Lets assume the scenario you describe for yielding a result of 2.

Given that 'i' is an integer with an initial value of 0, we begin our equation 'i = ++i'. We first evaluate the expression '++i' which means that the 'i' on both sides of the equation (which are, of course, one in the same) is now equal to 1. We've not yet gotten to the assignment, so it doesn't come into play just yet, but the '++' has been evaluated and eliminated from the equation, leaving us with 'i = i'. Since the value stored in 'i' is known to be '1', we can see that this equation reads as "store the value of 1 into the location i."

This is a logical explanation assuming what we already know: that the assignment is entirely redundant -- and here we've proven why.

I think the mistake you are making, is that you've confused the assignment operation taking place after the pre-increment, as repeating the increment on the new value, but that is not the case.

Share this post


Link to post
Share on other sites
Would a statement like this, be considered undefined as well ?

i = (i = i + 1);

To my mind the fact that there is no sequence point does not mean that the order of evaluation is not clearly indicated by the expression. Delaying the side-effect past a sequence point ( , or ;) by using a post increment in conjunction with an assignment both on the same cell is going to be iffy. I am not up to speed with the detail of the standard however so it is only an intuition.

Share this post


Link to post
Share on other sites
I think neither has undefined behavior, assuming it's C++.
Even with i++ instead of ++i, it would be defined.

Share this post


Link to post
Share on other sites
No, it's undefined behavior. From ISO/IEC 14882, section 5, paragraph 4:
Quote:
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. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.

Share this post


Link to post
Share on other sites
Sorry, and thanks for the standard quote.
My compiler is even issuing a warning for this code.
* moves to For Beginners *

Share this post


Link to post
Share on other sites
I don't believe this is undefined behavior, and if someone here could prove it, I would be shocked.

While what's been stated about sequence points is correct, that applies to situations such as x = ++i. This code is finding the address somewhere in the array x, and storing the result of the right side at that address. Because of this, depending on whether the left or right side is evaluated first changes the result.

In the case brought up here, that isn't as issue. Evaluating the left side will result in the same value regardless, so it boils down to whether the assignment can ever occur before the increment, and it can't. In this case, the behavior is well defined.

Share this post


Link to post
Share on other sites
Quote:
Original post by gekko
I don't believe this is undefined behavior, and if someone here could prove it, I would be shocked.

While what's been stated about sequence points is correct, that applies to situations such as x = ++i. This code is finding the address somewhere in the array x, and storing the result of the right side at that address. Because of this, depending on whether the left or right side is evaluated first changes the result.

No, that's just unspecified behavior when you don't know which one is executed first -- which applies to iterators and the like, but for plain types like int, SiCrane cited line and verse of the C++ standard which says why this is outright undefined behavior. I'm not sure how much more proven you can get beyond "This is exactly what the C++ standard says".

"shall have its stored value modified at most once" is violated by assigning to i with operator and incrementing i with ++i between sequence points. This doesn't apply to your example -- it only modifies i once with ++i (but it's still UB as that violates the other condition: "Furthermore, the prior value shall be accessed only to determine the value to be stored" -- the i in x is not read to determine the value to be stored.)

If you wish to argue against this, I'd suggest giving an example that violates the first bit -- "shall have its stored value modified at most once" -- and thus falling victim to UB, and then explaining what you feel makes that example different from i = ++i, which you're believing to not be UB.

Share this post


Link to post
Share on other sites
You cleared up a misunderstanding I had with that paragraph. I guess I'm officially shocked, though shouldn't be, it's C++.

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
Quote:
Original post by gekko
I don't believe this is undefined behavior, and if someone here could prove it, I would be shocked.

While what's been stated about sequence points is correct, that applies to situations such as x = ++i. This code is finding the address somewhere in the array x, and storing the result of the right side at that address. Because of this, depending on whether the left or right side is evaluated first changes the result.

No, that's just unspecified behavior when you don't know which one is executed first -- which applies to iterators and the like, but for plain types like int, SiCrane cited line and verse of the C++ standard which says why this is outright undefined behavior. I'm not sure how much more proven you can get beyond "This is exactly what the C++ standard says".

"shall have its stored value modified at most once" is violated by assigning to i with operator and incrementing i with ++i between sequence points. This doesn't apply to your example -- it only modifies i once with ++i (but it's still UB as that violates the other condition: "Furthermore, the prior value shall be accessed only to determine the value to be stored" -- the i in x is not read to determine the value to be stored.)

If you wish to argue against this, I'd suggest giving an example that violates the first bit -- "shall have its stored value modified at most once" -- and thus falling victim to UB, and then explaining what you feel makes that example different from i = ++i, which you're believing to not be UB.

Yeah many don't understand the restrictions with reading and writing to the same object between sequence points.
Just follow the following rule and you shouldn't fall foul of the rule restricting reading and writing to the same storage between sequence points:
Rule: Only use increment and decrement operators as full expressions. Do not have more than one assignment or compound assignment operator in a full expression.

In the context of C++'s unspecified order of evaluation of subexpressions, it's the only rule that can ensure safety.

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
I'm not sure how much more proven you can get beyond "This is exactly what the C++ standard says".

How about "this is almost identical to one that the C++ standard uses to illustrate undefined behavior"? Continuing the quote from my earlier post:
Quote:

[Example:

i = v[i++]; // the behavior is unspecified
i = 7, i++, i++; // i becomes 9
i = ++i + 1; // the behavior is unspecified
i = i + 1; // the value of i is incremented

-end example]

Share this post


Link to post
Share on other sites
Yes, you could get 2 if the implementation you are working with does not perform the increment operator as an assignment operator.

Consider the standard-compatible schema where almost all operations are performed on a remote processor with an extremely small memory, and the processor communicates with the actual memory through a channel that does not guarantee order of arrival. The only restriction is that on every sequence point, the processor waits for all previous memory requests to arrive before it continues, and that is enough to make it standard-compatible.

One way to run "i = ++i" would be to decompose it as:

grab i from memory, assign to X 
compute X + 1, assign to X
send X to memory to be stored in i (for ++)
send X to memory to be stored in i (for =)


Regardless of how you look at this, order of arrival of the two memory requests does not change the fact that only the value 1 is ever sent by the processor. Now, assume that the system instead sends a specific "increment" instruction to memory. One benefit would be that it's lighter than just assignment, because it doesn't have to carry the new value. The system then becomes:

grab i from memory, assign to X
compute X + 1, assign to X,
send increment order on variable i (for ++)
send X to memory to be stored in i (for =)


Now, it's possible for "i = X" to arrive before "++i", which would set i to 2.

Of course, such a system would be insane, so while it's possible it certainly isn't plausible. In practice, every sane modern processor commits incrementation back to memory as an assignment (or performs it atomically in a register), not as an incrementation instruction, and every sane compiler would perform "i = ++i" using atomic incrementation in a register instead of committing to memory.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement