Difference between i = ++i and ++i [duplicate] - c++

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)
What is the difference between i = ++i; and ++i; where i is an integer with value 10?
According to me both do the same job of incrementing i i.e after completion of both the expressions i =11.

i = ++i; invokes Undefined Behaviour whereas ++i; does not.
C++03 [Section 5/4] says 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.
In i = ++i i is being modified twice[pre-increment and assignment] without any intervening sequence point so the behaviour is Undefined in C as well as in C++.
However i = ++i is well defined in C++0x :)

Writing i = ++i; writes to variable i twice (one for the increment, one for the assignment) without a sequence point between the two. This, according to the C language standard causes undefined behavior.
This means the compiler is free to implement i = ++i as identical to i = i + 1, as i = i + 2 (this actually makes sense in certain pipeline- and cache-related circumstances), or as format C:\ (silly, but technically allowed by the standard).

i = ++i will often, but not necessarily, give the result of
i = i;
i +1;
which gives i = 10
As pointed out by the comments, this is undefined behaviour and should never be relied on
while ++i will ALWAYS give
i = i+1;
which gives i = 11;
And is therefore the correct way of doing it

If i is of scalar type, then i = ++i is UB, and ++i is equivalent to i+=1.
if i is of class type and there's an operator++ overloaded for that class then
i = ++i is equivalent to i.operator=(operator++(i)), which is NOT UB, and ++i just executes the ++ operator, with whichever semantics you put in it.

The result for the first one is undefined.

These expressions are related to sequence points and, the most importantly, the first one results in undefined behavior.

Related

why i = ++i + 2 is undefined behavior? [duplicate]

This question already has answers here:
New Sequence Points in C++11
(2 answers)
So why is i = ++i + 1 well-defined in C++11?
(3 answers)
Closed 4 years ago.
I've read something about order of evaluation and I understand some mistakes caused by order of evaluation.
My basic rule comes from a text and example:
Order of operand evaluation is independent of precedence and associativity.
In most cases, the order is largely unspecified.
So for expression like this: int i = f1() * f2();
f1 and f2 must be called before the multiplication can be done. After all, it is their results that are multiplied. However, we have no way of knowing whether f1 will be called before f2 or vice versa.
Undefined behavior examples:
int i = 0;
cout << i << " " << ++i << endl;
How I understand: I treat i and ++i as a function. I don't know which evaluates first, so the first i could be 0 or 1 and (the rule) makes sense.
while(beg != s.end())
*beg = toupper(*beg++); //Just another example.
I think the key to understand this is to treat each operand as a "evaluation unit", and one don't know order of evaluation within these units but can know order in every single unit.
But for i = ++i + 2 reference here, Why is it wrong? I can't explain with my own conclusion.
The left i is used as a lvalue and not a pointer. ++i simply rewrite the original value and doesn't change the storage address. What could be wrong if it evaluates first or latter? My rule fails here.
Quite long but try to provide enough background info, thank for your patience.
I don't know sequence point which is mentioned frequently in answers.. So I think I need to read something about it first. Btw, the debate is not very helpful, for a newbie simply want to know why is it considered wrong, like before C++11?
I find this answer Undefined behavior and sequence points explain well why i = ++i + 2 is undefined behaviour before C++11
C++11 has new sequencing rules. In particular, for a pre-increment (++i) the side effect (writing the new value) is sequenced-before the further use of the new, incremented value. Since the assignment i= is sequenced-after the evaluation of its right-hand side, this means the write ++i is transitively sequenced-before the write i=(++i + 2)
It would be another matter for i=(i++ + 2). For post-increment, the side effect is sequenced-after, which means the two assignments are no longer sequenced relatively to each other. That IS undefined behavior.
Your two "subfunctions" in i = ++i + 2 are an explicit assignment made by the = operator and an implicit assignment done by the ++ operator.
The preincrement operator is defined to return an incremented value of the variable, and this definitely shall be used for addition (performed by the + operator). However, it was not defined, when the incremented value should be stored back into i.
As a result, it was undefined whether the final value of i is old_i incremented plus 2 or just old_i incremented.

Behaviour of arr[i] = i++ and i = i + 1 statements in C and C++

In the C and C++ languages, the arr[i] = i++; statement invokes undefined behavior. Why does the statement i = i + 1; not invoke undefined behavior?
Since this was originally tagged with c and c++ and not any specific version(s), the below answer is a generic answer to the problem. However, please note for c++, C++17 onwards, the behaviour has changed. Please see this answer by Barry to know more.
For the statement
arr[i] = i++;
the value of i is used in both the operands, RHS(right-hand-side) and LHS(left-hand-side), and in one of the cases, the value is being modified (as a side effect of post ++) where there's no sequence point in between to determine which value of i should be considered. You can also check this canonical answer for more on this.
On the other hand, for i = i + 1, the value of i is used only in RHS, the computed result is stored in LHS, in other words, there's no ambiguity. We can write the same statement as i++, which
reads the value of i
Increments it by 1
stores it back to i
in a well-defined sequence. Hence, no issues.
Note that this will change in C++17. In C++17, arr[i] = i++ does not invoke undefined behavior. This is due to the following change in [expr.ass]:
In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression. The right operand is sequenced before the left operand.
That is, we do i++ then we do arr[i] then we perform the assignment. The now well-defined ordering is:
auto src = i++;
auto& dst = arr[i];
dst = src;
For C99, we have:
6.5 Expressions
Between the previous and next sequence point an object shall have its stored value
modified at most once by the evaluation of an expression. Furthermore, the prior value
shall be read only to determine the value to be stored.
In arr[i] = i++, the value of i is only modified once. But arr[i] also reads from i, and this value is not used to determine the new value of i. That's why it has undefined behavior.
On the other hand, in i = i + 1 we read i in order to compute i + 1, which is used as the new value of i. Therefore this expression is fine.
arr[i] = i++;
implies that
right hand expression is evaluated before assignment
subscript operator is evaluated before assignment
but contains ambiguity regarding the order of right hand expression evaluation and subscript operator evaluation, compiler is free to treat it as
auto & val{arr[i]};
i++;
auto const rval{i};
val = rval;
or as
i++;
auto & val{arr[i]};
auto const rval{i};
val = rval;
or as (same result as above)
i++;
auto const rval{i};
auto & val{arr[i]};
val = rval;
Which may produce unpredictable result, while
i = i + 1;
dos not have any ambiguity, right hand expression is evaluated before assignment:
auto const rval{i + 1};
auto & val{i};
val = rval;
or (same result as above)
auto & val{i};
auto const rval{i + 1};
val = rval;
In your example a [i] = i++, if i = 3 for example, do you think a [i] is evaluated first, or i++? In one case, the value 3 would be stored in a [3], in the other case, it would be stored in a [4]. It's obvious that we have a problem here. No sane person would dare writing that code unless they found a guarantee what exactly will happen here. (Java gives that guarantee).
What would you think could be a problem with i = i + 1? The language must read i first to calculate i+1, then store that result. There is nothing here that could be wrong. Same with a [i] = i+1. Evaluating i+1, unlike i++, doesn't change i. So if i = 3, the number 4 must be stored in a [3].
Various languages have various rules to fix the problem with a [i] = i++. Java defines what happens: Expressions are evaluated left to right including their side effects. C defines it as undefined behaviour. C++ doesn't make it undefined behaviour but just unspecified. It says that either a[i] or i++ is evaluated first, and the other one next, but it doesn't say which one. So unlike C where anything can happen, C++ defines that only one of two things can happen. Obviously that's one thing too many to be acceptable in your code.

Is the behaviour of i = i++ really undefined?

Possible Duplicate:
Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)
According to c++ standard,
i = 3;
i = i++;
will result in undefined behavior.
We use the term "undefined behavior" if it can lead to more then one result. But here, the final value of i will be 4 no matter what the order of evaluation, so shouldn't this really be called "unspecified behavior"?
The phrase, "…the final value of i will be 4 no matter what the order of evaluation…" is incorrect. The compiler could emit the equivalent of this:
i = 3;
int tmp = i;
++i;
i = tmp;
or this:
i = 3;
++i;
i = i - 1;
or this:
i = 3;
i = i;
++i;
As to the definitions of terms, if the answer was guaranteed to be 4, that wouldn't be unspecified or undefined behavior, it would be defined behavior.
As it stands, it is undefined behaviour according to the standard (Wikipedia), so it's even free to do this:
i = 3;
system("sudo rm -rf /"); // DO NOT TRY THIS AT HOME … OR AT WORK … OR ANYWHERE.
No, we don't use the term "undefined behavior" when it can simply lead to more than one arithmetical result. When the behavior is limited to different arithmetical results (or, more generally, to some set of predictable results), it is typically referred to as unspecified behavior.
Undefined behavior means completely unpredictable and unlimited consequences, like formatting the hard drive on your computer or simply making your program to crash. And i = i++ is undefined behavior.
Where you got the idea that i should be 4 in this case is not clear. There's absolutely nothing in C++ language that would let you come to that conclusion.
In C and also in C++, the order of any operation between two sequence points is completely up to the compiler and cannot be dependent on. The standard defines a list of things that makes up sequence points, from memory this is
the semicolon after a statement
the comma operator
evaluation of all function arguments before the call to the function
the && and || operand
Looking up the page on wikipedia, the lists is more complete and describes more in detail. Sequence points is an extremely important concept and if you do not already know what it means, you will benefit greatly by learning it right away.
1.
No, the result will be different depending on the order of evaluation. There is no evaluation boundary between the increment and the assignment, so the increment can be performed before or after the assignment. Consider this behaviour:
load i into CX
copy CX to DX
increase DX
store DX in i
store CX in i
The result is that i contains 3, not 4.
As a comparison, in C# there is a evaluation boundary between the evaulation of the expression and the assignment, so the result will always be 3.
2.
Even if the exact behaviour isn't specified, the specification is very clear on what it covers and what it doesn't cover. The behaviour is specified as undefined, it's not unspecified.
i=, and i++ are both side effects that modify i.
i++ does not imply that i is only incremented after the entire statement is evaluated, merely that the current value of i has been read.
As such, the assignment, and the increment, could happen in any order.
This question is old, but still appears to be referenced frequently, so it deserves a new answer in light of changes to the standard, from C++17.
expr.ass Subclause 1 explains
... the assignment is sequenced after the value computation of the right and left operands ...
and
The right operand is sequenced before the left operand.
The implication here is that the side-effects of the right operand are sequenced before the assignment, which means that the expression is not addressed by the provision in [basic.exec] Subclause 10:
If a side effect on a memory location ([intro.memory]) is unsequenced relative to either another side effect on the same memory location or a value computation using the value of any object in the same memory location, and they are not potentially concurrent ([intro.multithread]), the behavior is undefined
The behavior is defined, as explained in the example which immediately follows.
See also: What made i = i++ + 1; legal in C++17?
To answer your questions:
I think "undefined behavior" means that the compiler/language implementator is free to do whatever it thinks best, and no that it could lead to more than one result.
Because it's not unspecified. It's clearly specified that its behavior is undefined.
It's not worth it to type i=i++ when you could simply type i++.
I saw such question at OCAJP practice test.
IntelliJ's IDEA decompiler turns this
public static int iplus(){
int i=0;
return i=i++;
}
into this
public static int iplus() {
int i = 0;
byte var10000 = i;
int var1 = i + 1;
return var10000;
}
Create JAR from module, then import as library & inspect.

Error in the standards?

§5/4 C++ standard
i = 7, i++, i++; // i becomes 9
i = ++i + 1; //the behavior is unspecified
That should be changed to
i = 7, i++, i++; // the behavior is undefined
i = ++i + 1; //the behavior is undefined
right?
Yes, please see this defect report: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#351 .
Clarification: the example is wrong but your 'fix' is incorrect for the first statement. The first statement is correctly commented in the standard. It is only the second comment that is inaccurate.
i = 7, i++, i++; // i becomes 9
is perfectly fine. Operator = has higher precedence than ,so the expression is equivalent to
(i = 7), i++, i++;
which is perfectly well defined behaviour because , is a sequence point.
As far as
i = ++i + 1; //the behavior is unspecified
is concerned the behaviour is undefined in C++03 but well defined in C++0x. If you have the C++0x draft you can check out in section 1.9/15
i = i++ + 1; // the behavior is undefined
No, the standard is right. The comma operator guarantees that any side effects of previous operands are completed before evaluating the next.
These guarantees are provided by sequence points, which the comma operator (as well as && and ||) are.
Note that you are correct on the wording change for the second statement. It is undefined, not unspecified.
That should be changed to
i = 7, i++, i++; // the behavior is undefined
Why? The standard is correct, this shouldn’t be changed, and this behaviour is well-defined.
A comma (,) introduces a sequence point into the calculation so the order of execution is defined.

Is i += ++i undefined behavior in C++0x?

I'm very convinced with the explanation I've found that said that i = ++i is not undefined as far as C++0x is concerned, but I'm unable to judge whether the behavior of i += ++i is well-defined or not. Any takers?
The reasoning that makes i = ++i well-defined can equally be used to prove that i += ++i must also be well-defined.
i += ++i is equivalent to i += (i += 1) and the new sequencing rules require that the assignment takes place before the value-computation of the i += 1 sub-expression.
This means that the result of the expression i += ++i must be the same as for i = 2 * i + 1.
Edit: I have to revise my answer, because the behaviour is undefined after all.
The behaviour of i += ++i is undefined, because the value-computations of the sub-expressions i (left-hand side argument) and ++i are unsequenced in relation to each other and one of them contains an update of the object i.
This is not a problem for the expression i = ++i, because there the i on the left-hand side does not undergo an lvalue-to-rvalue conversion, which does happen in the i += ++i case.
On a side-note: Don't write such code in any serious project. It relies too much on exactly knowing the sequencing rules and there will be many people who either don't properly understand the sequencing rules, are unaware of the change in the rules that is the result of DR 637 or get tripped up by missing some important aspects of the expression in question (as happened to me when composing the first revision of this answer).