expression precedence

S

Smart Tag

Consider this:

int i = 7;
i = i++ + 1; // standard says this is undefined behavior

But, according to precedence rules, i = i++ + 1 means i = ((i++) + 1)
i.e, i should be 8. Why does the standard say it's undefined behavior?
 
F

Fred Zwarts

Smart Tag said:
Consider this:

int i = 7;
i = i++ + 1; // standard says this is undefined behavior

But, according to precedence rules, i = i++ + 1 means i = ((i++) + 1)
i.e, i should be 8. Why does the standard say it's undefined behavior?

It is not the expression at the right of the "=" that causes undefined behaviour.
It is the fact that i is assigned two values in one expression,
once with the "=" operator and once with the "++" operator.
 
S

Smart Tag

It is not the expression at the right of the "=" that causes undefined behaviour.
It is the fact that i is assigned two values in one expression,
once with the "=" operator and once with the "++" operator.

"assigned two values in one expression" - crystal clear. Thanks man!!!
 
J

Joshua Maurice

"assigned two values in one expression" - crystal clear. Thanks man!!!

Specifically, a primitive may not be assigned to twice between two
adjacent sequence points. Doing so is undefined behavior.

int i = 0;
int j = 0;
j = ++i;

The above "assigns two values in one expression", but it's allowed
because no single primitive variable is assigned to two or more
times.

int i = 0;
i = ++i;

The above is not allowed. i is assigned two twice between two adjacent
sequence points.

Further example:

void foo(int& x, int& y)
{ x = ++y; //undefined behavior if x aliases y.
}
int main()
{ int a = 0, b = 0;
foo(a, b); //fine
foo(a, a); //undefined behavior.
}
 
J

James Kanze

Consider this:
int i = 7;
i = i++ + 1; // standard says this is undefined behavior
But, according to precedence rules, i = i++ + 1 means i =
((i++) + 1) i.e, i should be 8. Why does the standard say it's
undefined behavior?

Because it does. It could just as easily have said that it was
defined behavior (as do other languages). But it prefers to
allow the implementation additional leeway with regards to when
side effects actually occur, and such things. Supposedly, this
allows for better optimization (although I've never seen a case
where it would make a difference, and the compiler couldn't have
done it anyway under the as if rule).
 
J

James Kanze

Specifically, a primitive may not be assigned to twice between
two adjacent sequence points. Doing so is undefined behavior.

To be complete, if a primitive is modified in an expression, it
may not be accessed (read or write) without an intervening
sequence point, other than a read-only access used to determine
the new value. Thus:

int i, j;
j = i + ++i; // undefined behavior !
i = i + 2; // defined, since the read access is
// used to determine the value written.
Further example:
void foo(int& x, int& y)
{ x = ++y; //undefined behavior if x aliases y.}
int main()
{ int a = 0, b = 0;
foo(a, b); //fine
foo(a, a); //undefined behavior.
}

Yes. This can be a real problem.
 
V

Victor Bazarov

Juha said:
Since calling a function is a sequence point, then I suppose this is
well-defined:

i = somefunction(i++, 1);
Yes.

Does that mean that if 'i' is of a type for which operator+ has been
defined, it makes "i = i++ + 1;" well-defined?

Well... Expression 'i++' has to yield the type "for which operator+ has
been defined", not 'i'. Of course it is reasonable to expect that those
are the same type. If so, then yes, of course.

V
 
J

James Kanze

Since calling a function is a sequence point, then I suppose this is
well-defined:
i = somefunction(i++, 1);
Yes.

Does that mean that if 'i' is of a type for which operator+
has been defined, it makes "i = i++ + 1;" well-defined?

Yes.

Just because something is well defined, of course, doesn't mean
that you have to do it:). Modifying the same (or even
different) variable twice in the same expression makes the code
harder to read and to understand.
 
J

James Kanze

Well... Expression 'i++' has to yield the type "for which
operator+ has been defined", not 'i'.

That's a good point, which I missed. If operator+ is user
defined, then so is operator++. So the only modification of i
here is the assignment (and unless the result of i++ + 1 is an
enum type, I think that has to be user defined as
well---although it sounds strange when expressed thusly, the
compiler generated assignment for class types is "user
defined"). So what his expression really is (supposing i is a
class type) is:
i.operator=( operator+( i.operator++(0), 1 ) );
or
i.operator=( i.operator++(0).operator+( 1 ) );
With sequence points all over the place, but no modification of
any variable (in the expression directly---if the various
functions take a non-const reference, which is to be expected,
then they might modify the variable).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,156
Messages
2,570,878
Members
47,404
Latest member
PerryRutt

Latest Threads

Top