views:

1848

answers:

15

Consider the following C++ Standard ISO/IEC 14882:2003(E) citation (section 5, paragraph 4):

Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified. 53) 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. [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]

I was surprised that i = ++i + 1 gives an undefined value of i. Does anybody know of a compiler implementation which does not give 2 for the following case?

int i = 0;
i = ++i + 1;
std::cout << i << std::endl;

The thing is that operator= has two args. First one is always i reference. The order of evaluation does not matter in this case. I do not see any problem except C++ Standard taboo.

Please, do not consider such cases where the order of arguments is important to evaluation. For example, ++i + i is obviously undefined. Please, consider only my case i = ++i + 1.

Why does the C++ Standard prohibit such expressions?

+10  A: 

C/C++ defines a concept called sequence points, which refer to a point in execution where it's guaranteed that all effects of previous evaluations will have already been performed. Saying i = ++i + 1 is undefined because it increments i and also assigns i to itself, neither of which is a defined sequence point alone. Therefore, it is unspecified which will happen first.

Charles Salvia
All this information is already stated in the question
Andreas Brinck
@Andreas: That doesn't invalidate the fact that this information is _the_ answer to the question. The question contains its own answer embedded within it.
Daniel Daranas
I'm confused how the pre-increment could be unspecified. The post-increment version I would understand, but in the given example I would have been sure the order must be [++i => i = 1][++i + 1 => 2][i=2]. Could you elaborate why that is wrong?
Sebastian
@Daniel My interpretation is that Alexsey already knows this but want to know why the standard is written as it is.
Andreas Brinck
@Sebastion, *you* may be sure that is the correct order, but any given compiler vendor may have a different idea. The point is, even though I agree that your understanding makes sense intuitively, there's no guarantee since in this case a pre-increment is not a sequence point.
Charles Salvia
@Andreas I agree. I myself answered with this interpretation in mind. But it's not that clearly worded, so answers which merely repeat reality as it is now don't surprise me.
Daniel Daranas
A: 

i = ++i + 1 isn't undefined. As you quoted, it is unspecified. This means that the compiler implementor can decide how they want to treat that case. It may be that every compiler implements it the same way, but that's not guaranteed.

jamessan
Why isn't it undefined? The paragraph quoted 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." and "The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined." This reads as undefined to me?
Charles Bailey
It *is* undefined. I don't think there is a formal distinction between unspecified and undefined in the standard.
Charles Salvia
Undefined, unspecified... Garbage. The same. Sorry my english. Why unspecified?
Alexey Malistov
The standard does distinguish between _undefined behaviour_, _unspecified behaviour_ (where there is usually are range of different allowed behaviours) and _implementation-defined behaviour_
Charles Bailey
The assignment `i = ++i + 1;` is an expression. 53) says that a scalar object cannot be modified twice in an expression. I think is *is* undefined.
Pascal Cuoq
Then either the OP misquoted the standard or the standard is conflating its own terminology between the description and the given examples.
jamessan
Pascal Cuoq
@jamessan I was puzzled about that too, but the OP does not help verify where he found these paragraph in the standard either.
Pascal Cuoq
Section 5, paragraph 4 seems pretty clear to me. It's where it is in my copy of the standard, at least.
Charles Bailey
@Charles @jamessan Ok, I found it (sorry!), and the line `i = ++i + 1; // the behavior is unspecified` *is* there. I believe all "unspecified" in this series of examples should have been "undefined". Some people do care about the distinction.
Pascal Cuoq
The standard defines the terms at 1.3.12 and 1.3.13, so you'd hope it is using them correctly.
jamessan
Iirc, "unspecified" is basically "it has to behave consistently and sanely, but compilers need not document their choice of behavior". Undefined is "may blow up the universe."
jalf
Its undefined, it was just an error in the standard, see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#351
mlvljr
To provide a bit of context, the error in the standard was in an example, where a line was listed as "unspecified". The examples are not normative (to translate from Standard-speak, they have no significance by themselves, but are only illustrations). I wound up filing a defect report myself about an example something like a decade ago. They happen.
David Thornley
Hm, interesting. Perhaps they should have many more (20?) examples on the sequence point topic then.
mlvljr
+7  A: 

The important part of the standard is:

its stored value modified at most once by the evaluation of an expression

You modify the value twice, once with the ++ operator, once with the assignment

Trent
I see that twice. And what? I want twice. Why undefined? Why is `i` equal to 2?
Alexey Malistov
@Alexey, are you asking why the standard says it's undefined? I don't know the answer to that, you will have to ask someone on the standards committee.
Trent
+6  A: 

Given two choices: defined or undefined, which choice would you have made?

The authors of the standard had two choices: define the behavior or specify it as undefined.

Given the clearly unwise nature of writing such code in the first place, it doesn't make any sense to specify a result for it. One would want to discourage code like that and not encourage it. It's not useful or necessary for anything.

Furthermore, standards committees do not have any way to force compiler writers to do anything. Had they required a specific behavior it is likely that the requirement would have been ignored.

There are practical reasons as well, but I suspect they were subordinate to the above general consideration. But for the record, any sort of required behavior for this kind of expression and related kinds will restrict the compiler's ability to generate code, to factor out common subexpressions, to move objects between registers and memory, etc. C was already handicapped by weak visibility restrictions. Languages like Fortran long ago realized that aliased parameters and globals were an optimization-killer and I believe they simply prohibited them.

I know you were interested in a specific expression, but the exact nature of any given construct doesn't matter very much. It's not going to be easy to predict what a complex code generator will do and the language attempts to not require those predictions in silly cases.

DigitalRoss
+1 "Given the clearly unwise nature of writing such code in the first place..."
Daniel Daranas
+31  A: 

It's undefined behaviour, not (just) unspecified behaviour because there are two writes to i without an intervening sequence point. It is this way by definition as far as the standard specifies.

The standard allows compilers to generate code that delays writes back to storage - or from another view point, to resequence the instructions implementing side effects - any way it chooses so long as it complies with the requirements of sequence points.

The issue with this statement expression is that it implies two writes to i without an intervening sequence point:

i = i++ + 1;

One write is for the value of the original value of i "plus one" and the other is for that value "plus one" again. These writes could happen in any order or blow up completely as far as the standard allows. Theoretically this even gives implementations the freedom to perform writebacks in parallel without bothering to check for simultaneous access errors.

Charles Bailey
Good explanation. It's probably easier to understand why this is undefined behavior by looking at the assembly code generated by different compilers.
Charles Salvia
Is it true that `i` may be equal to 1 in my sample (not yours)?
Alexey Malistov
Yes. It's undefined. It could be true that upon executing this line of code your computer turns into marshmallows.
GMan
Yes, that is correct, as the standard allows the compiler to execute those instructions in parallel.
Billy ONeal
Yes, it's certainly one possibility all though anything *could* happen. It's a little unfortunate that the standard uses examples that to show unspecified order of sub-expression evaluation that also invoke undefined behaviour without saying as much.
Charles Bailey
@GMan: or waffles.
Martinho Fernandes
You say "The standard allows compilers to generate code that delays write back to storage." Do this write explicit in Standard or it is your opinion?
Alexey Malistov
It's implementation defined. We don't do opinions around here. :) Compilers can be called standard-compliant if the code you compile with them behaves in accordance to the standard. Because this is undefined behavior, compilers can do *whatever they want*. They could reformat your computer before setting `i` to 123456789.
GMan
@GMan: It's true that a C implementation that turns your computer into marshmallows when executing `i = i++ + 1` is conforming perfectly with the standard, but I'd consider it a quality of implementation issue, and would be very unhappy with that implementation unless chocolate was involved.
David Thornley
Now I'm hungry...
Stefano Borini
Nuclear explosion, turning into marshmallows are known jokes. I'd like know more about delayed write. Is it declared in the Standard?
Alexey Malistov
Delayed writes aren't something that is explicitly mentioned in the standard, they are an implementation detail. If you look at all the requirements specified by the standard and you can design an implementation that conforms then it doesn't matter what it does under the covers so long as well-formed programs have the specified behaviours when run.
Charles Bailey
+3  A: 

i = v[i++]; // the behavior is unspecified
i = ++i + 1; // the behavior is unspecified

All the above expressions invoke Undefined Behavior.

i = 7, i++, i++; // i becomes 9

This is fine.

Read Steve Summit's C-FAQs.

Prasoon Saurav
`i = 7, i++, i++;` is ok.
Alexey Malistov
That's because , defines a new "sequence point"
Billy ONeal
no it is not ok! this is potential UB.
Prasoon Saurav
@Prasoon Could the fact that `,` is a sequence point be a particularity of C++ compared to C? The original question was about C++, not C.
Pascal Cuoq
No I dont think so, whether it is C or C++.... i=7,i++,i++; is potential UB, try compiling the code with gcc's -Wall option and check out the warnings :)
Prasoon Saurav
@Prasoon: `i=7,i++,i++;` looks perfectly clear to me, since the commas are sequence points. I don't have gcc handy right now, but if you'll list some of the warnings we'll tell you what they're saying, and if they're warranted. Remember that a conforming compiler may issue warning messages for anything it pleases, and if the gcc team thought writing that was a bad idea they had every right to issue warnings.
David Thornley
ok the warning that I am getting is "Operating on i may be undefined".Even now I think that it invokes potential UB. Since the assignment will be after the evaluation of either of the arguments(i in LHS or i++ on right most side because the order is unspecified and because = is not a sequence point it may invoke UB )I hope I am clear.
Prasoon Saurav
@Prasoon: The order is specified by the commas. Any operation to the left of a comma is finished before anything on the right is started (or at least that's the effect). `=` isn't a sequence point, but it's got higher precedence than `,`. gcc is probably issuing a general warning (note the "may be undefined") that doesn't apply in this case. Note that this applies to the comma operator, not the comma separating function parameters (`f(i++, i++)` is undefined behavior).
David Thornley
Notice that GCC can also be trapped the other way around. The following invokes undefined behavior, but GCC does not warn: `i = (i, ++i, i) + 1;` - its analysis is not that sophisticated.
Johannes Schaub - litb
@ David Thornley : Now you say that = isn't a sequence point but it has got a higher precedence than ',' but that has nothing to do with the order of evaluation, it is still unspecified.
Prasoon Saurav
@Iitb: i = (i, ++i, i) + 1; looks perfectly clear to me, how is it invoking UB? In i=7,i++,i++; not all the side effects are completed after the second comma operator, there is still one i++ operation left, now suppose it takes place just before the assignment, then don't you think that the value of 'i' is modified twice between two sequence points ',' and ';'.
Prasoon Saurav
@Prasoon, this has nothing to do with `i=7, i++, i++;`: The binding is `(i=7),i++,i++`, and evaluation is left-to-right, and there is a sequence point between each evaluation - so you don't change anything twice between two immediate sequence points. But in `i = (i, i++, i) + 1` you *do*: While there is a sequence point between each of the three `i, i++, i`, there is no sequence point between the assignment and `i++`. This means the side effect of the assignment is not sequenced after or before `i++`: It can happen between the same sequence points surrounding `i++`, in which case UB happens.
Johannes Schaub - litb
What you need is something like "in an assignment, the actual assignment is evaluated after the evaluations of both operands". In that case, the assignment will not happen before each of the sequence points within the right side, because sequence points state that "... all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place.". But as the order of evaluation is unspecified, it can happen the assignment is within the same sequence points as is the increment: These two are *not* sequenced with respect to each other.
Johannes Schaub - litb
@Prasoon, and notice what happens in `i=7, i++, i++;`: Sequence points mean that no side effects of subsequent evaluations shall have taken place yet: The evaluations of the comma-operator operands however happen from left-to-right, which means the last "i++", which is a subsequent evaluation, does not happen before the "i=7" because of the seq point after "i=7", which is a previous evaluation.
Johannes Schaub - litb
I missed the binding in i=7,i++,i++; thanks for the precise explanation.
Prasoon Saurav
@litb: Still "there is no sequence point between the assignment and i++." is not clear.The expression is i=(i,i++,i)+1; now in i,i++,i all the side effects of the previous subexpressions are complete after the sequence point(comma operator here), that means the comma operator after i++ clears all the side effects before it ,so how is your statement valid, or am I missing something?
Prasoon Saurav
@Prasoon, Yes the sequence point after `i++` completes all side effects before it, but there is nothing that stops the assignment side effect overlapping with the side effect of `i++`. The underlying problem is that the side effect of an assignment is not specified to happen after or before the evaluation of both operands of the assignment, and so sequence points cannot do anything with regard to protecting this: Sequence points induce a *partial* order: Just because there is a sequence point after and before `i++` doesn't mean *all* side effects are sequenced with regard to it.
Johannes Schaub - litb
Also, notice that merely a sequence point means nothing: The order of evaluations isn't dictated by the form of code. It's dictated by semantic rules. In this case, there is no semantic rule saying when the assignment side effect happens with regard to evaluating both of its operands or subexpressions of those operands.
Johannes Schaub - litb
@litb:"Sequence points induce a partial order:" This was enough, thanks :).
Prasoon Saurav
@litb:You said "Sequence points induce a partial order: Just because there is a sequence point after and before i++ doesn't mean all side effects are sequenced with regard to it"But as far as I know "At certain specified points in the execution sequence called sequence points,all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place."Since,comma operators also specify execution order the side effect of i++ have been cancelled when you reach the last i.you would have been right had the order of evaluation been not specified
Prasoon Saurav
@litb: Please give a reply to my above post. :-)
Prasoon Saurav
@Prasoon alright let's do an example of a possible order of side effects. `<a>` is assignment, and `<n>` is an increment. `:s:` is a sequence point. Then the side effects can be sequenced as follows between sequence points: `(i :s: i++<a><n> :s: i) + 1`. The value of the scalar `i` was changed twice between the first and second sequence point here. The order in which the assignment and the increment happens is unspecified, and since between them there is no sequence point, it is not even atomic with respect to each other. This is one allowed ordering [...]
Johannes Schaub - litb
[...] permitted by the unspecified ordering of these side effects. This is different to `(i++, i++)`, because the evaluation order of the two subexpressions is from left to right, and at the sequence point between them, the increment of the previous evaluation shall be complete, and the next increment shall not have yet taken place. This enforces that there is no change of the value of i between two sequence points, which makes `(i++, i++)` valid.
Johannes Schaub - litb
@litb: I think the sequence (i :s: i++<a><n> :s: i) + 1 is not valid because:6.5.16.1 (2) In simple assignment (=), the value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand.i.e. the value of the right operand needs to be known before the assignment side effect (modification of the value stored in the object corresponding to the left operand)
Prasoon Saurav
contd....: 6.5.17 (2) The left operand of a comma operator is evaluated as a void expression; there is a sequence point after its evaluation. Then the right operand is evaluated; the result has its type and value.i.e. the rightmost operand of the comma operation needs to be evaluated to know the value and type of the comma expression (and the value of the right operand for our example).
Prasoon Saurav
@litb: So in this case, the 'previous sequence point' for the assignment side effect would, in effect, be the right-most comma operation. The possible sequence mentioned by you is invalid.
Prasoon Saurav
@Prasoon, value computation and initiation of side effects are two different things (see the accepted answer - it's completely right here). The compiler can completely see that in this one: `x = y++` x will be assigned `y+1`, before incrementing y, as it can completely see in the above that `i` is going to be assigned `i+2` - and can sequence the assignment together, and overlapping, with the increment of `i`. This is what makes it UB. My analysis was about C++, anyway, but there is not a difference to behavior in C, i believe.
Johannes Schaub - litb
@Johannes : "value computation and initiation of side effects are two different thing"I know that but:See Keith's post herehttp://groups.google.co.in/group/comp.lang.c/browse_thread/thread/1a4803243bb8bd6b
Prasoon Saurav
Wow there are lots of opinions there. Good question! I will post my opinion to there later today. Have to head to work. Seeya xD
Johannes Schaub - litb
Bbye, will wait for your post there :)
Prasoon Saurav
Seriously, i don't know anymore what i believe about this for C99 xD I think it is undefined behavior, or at least very underspecified and not nearly safe to use in ones own code :(. But for C1x and C++0x, the discussion showed the code is not undefined behavior, i think. Have fun
Johannes Schaub - litb
+4  A: 

Assuming you are asking "Why is the language designed this way?".

You say that i = ++i + i is "obviously undefined" but i = ++i + 1 should leave i with a defined value? Frankly, that would not be very consistent. I prefer to have either everything perfectly defined, or everything consistently unspecified. In C++ I have the latter. It's not a terribly bad choice per se - for one thing, it prevents you from writing evil code which makes five or six modifications in the same "statement".

Daniel Daranas
I don't follow, the expression '++i + 1' is not an ordering problem. The problem with 'i = ++i + 1' is with the assignment to i and the increment of i between the same sequence points.
Trent
@Trent: You didn't follow because it was badly expressed. You are right, the problem is between the increment and the assignment. I have reworded it now.
Daniel Daranas
+3  A: 

Argument by analogy: If you think of operators as types of functions, then it kind of makes sense. If you had a class with an overloaded operator=, your assignment statement would be equivalent to something like this:

operator=(i, ++i+1)

(The first parameter is actually passed in implicitly via the this pointer, but this is just for illustration.)

For a plain function call, this is obviously undefined. The value of the first argument depends on when the second argument is evaluated. However with primitive types you get away with it because the original value of i is simply overwritten; its value doesn't matter. But if you were doing some other magic in your own operator=, then the difference could surface.

Simply put: all operators act like functions, and should therefore behave according to the same notions. If i + ++i is undefined, then i = ++i should be undefined as well.

int3
The value of the first argument depends. But the reference does not depend. It is impossible to overload operator= without passing the reference of `i`.
Alexey Malistov
I'm not sure what you mean.. yeah the first argument is a reference and not a value, I fuzzed over that, but in an overloaded operator you could retrieve the value of the first argument via the reference, and perform some computations that depended on it.
int3
+43  A: 

You make the mistake of thinking of operator= as a two-argument function, where the side effects of the arguments must be completely evaluated before the function begins. If that were the case, then the expression i = ++i + 1 would have multiple sequence points, and ++i would be fully evaluated before the assignment began. That's not the case, though. What's being evaluated in the intrinsic assignment operator, not a user-defined operator. There's only one sequence point in that expression.

The result of ++i is evaluated before the assignment (and before the addition operator), but the side effect is not necessarily applied right away. The result of ++i + 1 is always the same as i + 2, so that's the value that gets assigned to i as part of the assignment operator. The result of ++i is always i + 1, so that's what gets assigned to i as part of the increment operator. There is no sequence point to control which value should get assigned first.

Since the code is violating the rule that "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," the behavior is undefined. Practically, though, it's likely that either i + 1 or i + 2 will be assigned first, then the other value will be assigned, and finally the program will continue running as usual — no nasal demons or exploding toilets, and no i + 3, either.

Rob Kennedy
this seems to be the crux of the matter, OP is assuming operator= is a sequence point
jk
+1 "no nasal demons or exploding toilets"
nalply
I think this answer most directly addresses the OP's source of confusion. Since `i` is an integral type (as opposed to a class with an overloaded `=` operator), there is no sequence point for `operator =`, because `operator =` is not a function call.
Charles Salvia
+1 because I understood your explanation
Sebastian
By the way, i have not found `intrinsic` word in C++ Standard. Why built-in `operator=` is not sequence point as any function?
Alexey Malistov
Alexey, I suggest you ask that as a separate question. It goes toward the general theme of *parity* between built-in stuff and user-defined stuff. (*Intrinsic* doesn't need to appear in the standard for the word to have meaning. It's simply a synonym for *built-in*, for things the compiler just knows about without having been told.)
Rob Kennedy
@nalply: And if a [hi-tech] toilet waste disposal system's firmware gets '2' instead of '1' as a pressure coefficient somewhere?
mlvljr
+1  A: 

The underlying reason is because of the way the compiler handles reading and writing of values. The compiler is allowed to store an intermediate value in memory and only actually commit the value at the end of the expression. We read the expression ++i as "increase i by one and return it", but a compiler might see it as "load the value of i, add one, return it, and the commit it back to memory before someone uses it again. The compiler is encouraged to avoid reading/writing to the actual memory location as much as possible, because that would slow the program down.

In the specific case of i = ++i + 1, it suffers largely due to the need of consistent behavioral rules. Many compilers will do the 'right thing' in such a situation, but what if one of the is was actually a pointer, pointing to i? Without this rule, the compiler would have to be very careful to make sure it performed the loads and stores in the right order. This rule serves to allow for more optimization opportunities.

A similar case is that of the so-called strict-aliasing rule. You can't assign a value (say, an int) through a value of an unrelated type (say, a float) with only a few exceptions. This keeps the compiler from having to worry that some float * being used will change the value of an int, and greatly improves optimization potential.

coppro
What is the "right thing"? The standard can either say what a right thing is, constraining possibilities for optimization, or leave it undefined. It's a judgment call.
David Thornley
I meant the value that you'd come across by normal evaluation; which would be to store the value of i + 2 in i.
coppro
+1  A: 

The problem here is that the standard allows a compiler to completely reorder a statement while it is executing. It is not, however, allowed to reorder statements (so long as any such reordering results in changed program behavior). Therefore, the expression i = ++i + 1; may be evaluated two ways:

++i; // i = 2
i = i + 1;

or

i = i + 1;  // i = 2
++i;

or

i = i + 1;  ++i; //(Running in parallel using, say, an SSE instruction) i = 1

This gets even worse when you have user defined types thrown in the mix, where the ++ operator can have whatever effect on the type the author of the type wants, in which case the order used in evaluation matters significantly.

Billy ONeal
If you have user-defined types, the problem goes away completely; the code in question wouldn't be undefined at all. The increment operator would occur, then the addition operator, and finally the assignment operator. And there'd be sequence points between each of those operators, too.
Rob Kennedy
+2  A: 

How about, we just all agree to never, never, write code like this? If the compiler doesn't know what you want to do, how do you expect the poor sap that is following on behind you to understand what you wanted to do? Putting i++; on it's own line will not kill you.

Ken Lange
A: 

From ++i, i must assigned "1", but with i = ++i + 1, it must be assigned the value "2". Since there is no intervening sequence point, the compiler can assume that the same variable is not being written twice, so this two operations can be done in any order. so yes, the compiler would be correct if the final value is 1.

Mister
+5  A: 

Please note that your copy of the standard is outdated and contains a known (and fixed) error just in 1st and 3rd code lines of your example, see:

C++ Standard Core Language Issue Table of Contents, Revision 67, #351

and

Andrew Koenig: Sequence point error: unspecified or undefined?

The topic is not easy to get just reading the standard (which is pretty obscure :( in this case).

For example, will it be well(or not)-defined, unspecified or else in general case actually depends not only on the statement structure, but also on memory contents (to be specific, variable values) at the moment of execution, another example:

++i, ++i; //ok

(++i, ++j) + (++i, ++j); //ub, see the first reference below (12.1 - 12.3)

Please have a look at (it has it all clear and precise):

JTC1/SC22/WG14 N926 "Sequence Point Analysis"

Also, Angelika Langer has an article on the topic (though not as clear as the previous one):

"Sequence Points and Expression Evaluation in C++"

There was also a discussion in Russian (though with some apparently erroneous statements in the comments and in the post itself):

"Точки следования (sequence points)"

mlvljr
+1 for the russian link.
Alexey Malistov
Thanks, but beware the author is wrong on the 'int a, b, c; a = b = c = 0;' thing (the order of assignment is strictly specified by the operator precedence rules, and there are actually no variable reads here, as there are no in 'int i = 0;' ).
mlvljr
+3  A: 

The following code demonstrates how you could get the wrong(unexpected) result:

int main()
{
  int i = 0;
  __asm { // here standard conformant implementation of i = ++i + 1
    mov eax, i;
    inc eax;
    mov ecx, 1;
    add ecx, eax;
    mov i, ecx;

    mov i, eax; // delayed write
  };
  cout << i << endl;
}

It will print 1 as a result.

Kirill V. Lyadvinsky