Jump to content
  • Advertisement
Sign in to follow this  
nullsquared

i=i++, sequence points (C++)

This topic is 3046 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

i = i++;
I'm sure we've all seen that. Assuming i is a primitive type (such as int), is the behavior undefined? I've read that it is indeed undefined since the = operator does not introduce a sequence point (*). Is this correct? I don't fully understand why, though. The post-fix ++ operator increments by 1 and returns the old value, right? And then this old value will be assigned to i, effectively nullifying the change. (*) Unless i is a non-primitive type and operator=() is overloaded, apparently. In which case it would introduce a sequence point because it is treated as a normal function, and therefore i++ would be fully evaluated before operator=() is actually called. Would any of the C++ gurus like to shed some light on this?

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by Sirisian
Quote:
Original post by nullsquared
Assuming i is a primitive type (such as int), is the behavior undefined?

Sequence Points 3rd paragraph.

Also open up the C++ standard and go to section 5.0.4.

Also this: sequence points.


Yes, I've seen these sources. Thus the "I've read that it is indeed undefined [...]". Further more, did you read the part of my post involving "I don't fully understand why, though [...]"?

Share this post


Link to post
Share on other sites
Your sentences "The post-fix ++ operator increments by 1 and returns the old value, right? And then this old value will be assigned to i, effectively nullifying the change." rely heavily on the assumption that the increment will take place before the assignment.

You have to forget about the semantics of the operators involved. It is obvious by looking at the code to see what the programmer intended (well, a sane programmer). But the compiler is a machine, it sees a statement that involves two assignments, neither of which has priority over the other.

Share this post


Link to post
Share on other sites
Right; what I'm asking is what goes on behind the scenes. The way I see it, i++ is a single self contained operation - "increment, return old value." Obviously it's not a single instruction in assembly. Thus I want to understand how a non-overloaded operator= works such that it may cause undefined behavior in this case. How would the assembly get mixed up such that one happens before the other, considering operator= has lower precedence than operator++(int)?

If it was something like operator=(int &lhs, int rhs) and you called operator=(i, i++) then it would work fine because both parameters would be evaluated before the function is actually executed; clearly this isn't the case, however, thus my question.

Share this post


Link to post
Share on other sites
Undefined behavior has nothing to do with assembly getting "mixed up". The C++ language defines sequence points that dictate when and where you may modify a variable in a given expression. If you violate these specific rules, you will have undefined behavior on your hands, regardless of what your particular compiler does with the resulting assembly.

Quote:
If it was something like operator=(int &lhs, int rhs) and you called operator=(i, i++) then it would work fine because both parameters would be evaluated before the function is actually executed; clearly this isn't the case, however, thus my question.

The order of evaluation of parameters isn't specified and there is no sequence point there I believe, which would make that undefined behavior as well.

Share this post


Link to post
Share on other sites
Interestingly, this is the assembly that MSVC 2008 spat out in debug mode for i = i++:

mov eax, DWORD PTR _i$[ebp]
mov DWORD PTR _i$[ebp], eax
mov ecx, DWORD PTR _i$[ebp]
add ecx, 1
mov DWORD PTR _i$[ebp], ecx

i gets loaded into a register, immediately reassigned back to itself, reloaded, incremented and then assigned back to itself.

Share this post


Link to post
Share on other sites
Quote:
Original post by Mike.Popoloski
Undefined behavior has nothing to do with assembly getting "mixed up". The C++ language defines sequence points that dictate when and where you may modify a variable in a given expression. If you violate these specific rules, you will have undefined behavior on your hands, regardless of what your particular compiler does with the resulting assembly.

I understand that, I'm just trying to figure out if that's just an arbitrary decision by the standard or if there is some underlying issue/reason.

Quote:
Quote:
If it was something like operator=(int &lhs, int rhs) and you called operator=(i, i++) then it would work fine because both parameters would be evaluated before the function is actually executed; clearly this isn't the case, however, thus my question.

The order of evaluation of parameters isn't specified and there is no sequence point there I believe, which would make that undefined behavior as well.

The sequence point is before the function code is executed, which means both i and i++ will be evaluated. The reference will refer to the variable i, and i++ will return a copy of the old value of i:

// pseudo code
int i = 2;
operator=(i, i++);
operator=(int &lhs, int rhs)
{
// lhs is i, which == 3
// rhs is a copy of the old value of i, which is 2
lhs = rhs; // i == 2 again
}

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
Interestingly, this is the assembly that MSVC 2008 spat out in debug mode for i = i++:

mov eax, DWORD PTR _i$[ebp]
mov DWORD PTR _i$[ebp], eax
mov ecx, DWORD PTR _i$[ebp]
add ecx, 1
mov DWORD PTR _i$[ebp], ecx

i gets loaded into a register, immediately reassigned back to itself, reloaded, incremented and then assigned back to itself.


That's really interesting.

Share this post


Link to post
Share on other sites
Quote:
Original post by nullsquared
The sequence point is before the function code is executed, which means both i and i++ will be evaluated. The reference will refer to the variable i, and i++ will return a copy of the old value of i:

// pseudo code
int i = 2;
operator=(i, i++);
operator=(int &lhs, int rhs)
{
// lhs is i, which == 3
// rhs is a copy of the old value of i, which is 2
lhs = rhs; // i == 2 again
}


There is no sequence point between parameters, which means you are modifying a variable without a sequence point in between, which means it is undefined behavior, no matter whether it appears to work or not.

Share this post


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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!