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

Started by
19 comments, last by Makaan 14 years, 2 months ago
Quote:
Right; what I'm asking is what goes on behind the scenes.

That depends on the specific compiler.

Quote:
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.

It doesn't matter whether or not it's a single assembly instruction; nor does it matter whether you conceptualize the operation as a single one or an aggregation of many operations. The assembly and the precedence of the operators doesn't matter. What matters is what the C++ standard says, and the standard explicitly calls modification of a scalar value more than once between sequence points "undefined."

Quote:
Thus I want to understand how a non-overloaded operator= works such that it may cause undefined behavior in this case.

It will cause undefined behavior. Always.

Remember, undefined behavior (in the sense of the C++ standard) isn't necessarily going to have apparently malignant results. It can, in fact, do exactly what you would think it correct and logical. That does not preclude it from being undefined behavior. Undefined behavior is the standard saying "we do not account for this scenario" or "we do not consider this scenario to be well-formed" even those it is syntactically valid. Thus, compilers are free to behave however they like. In practice this generally might translate for "do not write code to detect or handle this case," thus the compiler continues code generation as normal. This may cause the compiler to produce code that would crash, or perform an operation out of order... it may cause the compiler to produce slightly different code each time (maybe some sort or algorithm isn't stable under these conditions, for example) -- it all really depends on how the compiler is implemented.

Advertisement
Quote:Original post by Mike.Popoloski
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.

I'm pretty sure this isn't undefined behavior. You need to modify the value multiple times between sequence points to rise to undefined behavior, and the value is only modified once.
Quote:Original post by SiCrane
Quote:Original post by Mike.Popoloski
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.

I'm pretty sure this isn't undefined behavior. You need to modify the value multiple times between sequence points to rise to undefined behavior, and the value is only modified once.


Ah yes, jpetrie was just informing me of that. This just reinforces the idea that you shouldn't try to dance around the issue trying to be tricky, since it will most likely come back to bite you.
Mike Popoloski | Journal | SlimDX
Quote:Original post by Mike.Popoloski
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.


As SiCrane points out, I don't believe that's undefined behavior. If you passed ++i as the first parameter and i++ as the second, then that would undefined.

Quote:
Remember, undefined behavior (in the sense of the C++ standard) isn't necessarily going to have apparently malignant results.

jpetrie, you're right. I'm basing decisions on an incorrect definition of undefined [smile].

Edit:
Interesting enough, here is GCC's version:
	movl	$1337, 12(%esp) // int i = 1337;	incl	12(%esp)        // i = i++;

It increments i and doesn't even assign it back to itself.

Then again, it also says,
D:\programming\test_sequence_points\main.cpp:4: warning: operation on 'i' may be undefined

[grin]

Anyways, thanks for the discussion.
Quote:Original post by SiCrane
Quote:Original post by Mike.Popoloski
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.

I'm pretty sure this isn't undefined behavior. You need to modify the value multiple times between sequence points to rise to undefined behavior, and the value is only modified once.
But the order of evaluation of parameters is undefined, so the output of printf("%d %d", i, i++) is not predictable, is it?

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Yes, I believe the standard calls it unspecified behavior rather than undefined behavior.
Quote:Original post by nullsquared
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.

It allows for more aggressive optimizers. Consider:
*a = (*b)++;

What this rule means is that if a and b point to the same object, undefined behavior occurs. Let's reword that: The optimizer can act under the assumption that a and b don't point to the same thing, because it would be undefined behavior if they did. In this example, there's not much more optimization we can do based on this -- but we do still gain a little in that the optimizer doesn't have to be quite as strict about the order of operation.

Quote:Original post by SiCrane
Yes, I believe the standard calls it unspecified behavior rather than undefined behavior.

I believe it (printf("%d %d", i, i++)) still runs afoul of:
Quote:The C++ Standard, 5¶4, emphasis added:

4 Except where noted, the order of evaluation of operands of individual operators and subexpressions of indi-
vidual 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.

And thus is still undefined behavior.

The canonical example of f(a(),b()); does have merely 'unspecified' behavior as to whether a() or b() executes first.

[Edited by - MaulingMonkey on February 13, 2010 6:24:43 PM]
i get something else from gcc for:
int i;i = i++;

it is just :
add dword ptr [ebp-0x10],0x1

and i get no warnings.
Did you use -Wall -pedantic ? I noticed codepad gets it.
Quote:Original post by Makaan
i get something else from gcc for:
int i;i = i++;

it is just :
add dword ptr [ebp-0x10],0x1

and i get no warnings.


What version of GCC? 4.4.2 here not only gives me the undefined behavior warning but also "warning: 'i' is used uninitialized in this function". And it generates this assembly:
incl	12(%esp)

This topic is closed to new replies.

Advertisement