Velocity Reviews > Does this cause undefined behaviour?

# Does this cause undefined behaviour?

ozbear
Guest
Posts: n/a

 12-30-2003
Someone was asking in another forum how to translate:
if (x && (y1=(y+y1)/2)) /* all integers with defined values */
to another language.

I am at odds with myself as to whether this causes undefined behaviour

in the first place. Does the subexpression (y1=(y+y1)/2)
cause UB because /y/ is both modified and used without an
intervening sequence point attached to the larger expression
or is it ok because the value of the assignment is the left
hand side is used?

In otherwords, the simple statement:

y = (y+y1)/2;

is well defined assuming reasonable values for y and y1 but when
used in a larger expression as above does it become UB since
/y/ is now both modified and used?

Or, is it ok since /y/ isn't actually used in the larger
expression but the well-defined value assigned to it?

My question would equally apply, I think, to something like...

x = y = (y+y2)/2; /* ok, not ok, or bad analogy? */

Regards, Oz

Joona I Palaste
Guest
Posts: n/a

 12-30-2003
ozbear <(E-Mail Removed)> scribbled the following:
> Someone was asking in another forum how to translate:
> if (x && (y1=(y+y1)/2)) /* all integers with defined values */
> to another language.

> I am at odds with myself as to whether this causes undefined behaviour

> in the first place. Does the subexpression (y1=(y+y1)/2)
> cause UB because /y/ is both modified and used without an
> intervening sequence point attached to the larger expression
> or is it ok because the value of the assignment is the left
> hand side is used?

ITYM /y1/, not /y/, there.

> In otherwords, the simple statement:

> y = (y+y1)/2;

> is well defined assuming reasonable values for y and y1 but when
> used in a larger expression as above does it become UB since
> /y/ is now both modified and used?

No, I don't think it becomes UB, unless your larger expression
modifies or uses /y1/ (again, ITYM that) in a different place.

> Or, is it ok since /y/ isn't actually used in the larger
> expression but the well-defined value assigned to it?

Yes, I think that's the case.

> My question would equally apply, I think, to something like...

> x = y = (y+y2)/2; /* ok, not ok, or bad analogy? */

It's a good analogy. That expression is, AFAIK, completely safe.
What would cause UB would be y = y = (y+y2)/2, modifying y twice
without intervening sequence points, but your expression above
doesn't do that.

--
/-- Joona Palaste ((E-Mail Removed)) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/

Ben Pfaff
Guest
Posts: n/a

 12-30-2003
http://www.velocityreviews.com/forums/(E-Mail Removed) (ozbear) writes:

> Someone was asking in another forum how to translate:
> if (x && (y1=(y+y1)/2)) /* all integers with defined values */
> to another language.
>
> I am at odds with myself as to whether this causes undefined behaviour
> in the first place. Does the subexpression (y1=(y+y1)/2)
> cause UB because /y/ is both modified and used without an
> intervening sequence point attached to the larger expression
> or is it ok because the value of the assignment is the left
> hand side is used?

No, this subexpression is well-defined, for the same reason that
`x = x + 1' is well-defined.

> In otherwords, the simple statement:
>
> y = (y+y1)/2;
>
> is well defined assuming reasonable values for y and y1 but when
> used in a larger expression as above does it become UB since
> /y/ is now both modified and used?

Not in this case: y (and y1) aren't mentioned in the larger
expression other than in that subexpression. Furthermore, there
is a sequence point between the left and right side of &&.

--
int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv wxyz.\
\n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
);while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\
);}return 0;}

Kevin Goodsell
Guest
Posts: n/a

 12-30-2003
Joona I Palaste wrote:

> ozbear <(E-Mail Removed)> scribbled the following:
>
>> x = y = (y+y2)/2; /* ok, not ok, or bad analogy? */

>
>
> It's a good analogy. That expression is, AFAIK, completely safe.
> What would cause UB would be y = y = (y+y2)/2, modifying y twice
> without intervening sequence points, but your expression above
> doesn't do that.
>

Undefined behavior also results from /using/ the value of an object (for
some purpose other than determining its new value) and also modifying it
without an intervening sequence point. But in this case, the object is
only used for determining the new value.

So this is obviously undefined because it modifies i twice:

i = a[i++];

but this is also undefined, even though it does not modify anything
multiple times:

a[i++] = i;

-Kevin
--
My email address is valid, but changes periodically.

Martin Dickopp
Guest
Posts: n/a

 12-30-2003
(E-Mail Removed) (ozbear) writes:

> Does the subexpression (y1=(y+y1)/2) cause UB because /y/ is both
> modified and used without an intervening sequence point

It is not necessarily undefined behavior to modify an object and use its
value without intervening sequence point. Essentially, there are two rules
(with respect to the modification of objects) about what is allowed
between two sequence points:

(1) The value of the object may be modified at most once.
(2) If the value of the object is modified at all, the previous value
may be used only to determine the new value.

The standard gives two examples of undefined behavior:

i = ++i + 1; violates (1), because the value of `i' is modified
twice.
a[i++] = i; violates (2). While `i' is modified only once, its
previous value is used to determine its storage
location (as opposed to its new value).

Martin

Horst Kraemer
Guest
Posts: n/a

 12-31-2003
On Tue, 30 Dec 2003 21:59:29 GMT, (E-Mail Removed) (ozbear) wrote:

> In otherwords, the simple statement:
>
> y = (y+y1)/2;
>
> is well defined assuming reasonable values for y and y1 but when
> used in a larger expression as above does it become UB since
> /y/ is now both modified and used?

No. The behaviour of an expression which is modifying an object and
using the value of this object without intervening sequence point
would only be undefined if a serial execution of the read and write
accesses to the object could possibly occur either in the order
old value of y is needed to determine the new value stored to y.

The behaviour of the expression /*X*/ in

int x,y=0;

x = y + (y=3) /*X*/;

is undefined because read|write could occur in either order. Note that
the reason for undefinedness is not primarily the fact that -
depending on the order of evaluation of the subexpressions - the
result could be either 0+3=3 or 3+3=6 but the bare fact that the read
for <y=3>.

--
Horst

Richard Bos
Guest
Posts: n/a

 12-31-2003
(E-Mail Removed) (ozbear) wrote:

> My question would equally apply, I think, to something like...
>
> x = y = (y+y2)/2; /* ok, not ok, or bad analogy? */

An additional point: it may seem that this causes undefined behaviour,
because

- a new value is computed for y (involving y, but that part is OK);
- the value of y is then assigned to x, without an intervening
sequence point.

However, this is not what happens. _This_ is:

- a new value is computed for y (involving the old y in an OK manner);
- that same _value_ is also the value of the assignment _expression_,
which is then assigned to x.

IOW, the evaluation of the inner assignment expression does not, in the
abstract machine, read y again; it evaluates its right hand side, and
then _both_ assigns this to y _and_ passes it on to the outer
assignment.

Richard

Martin Dickopp
Guest
Posts: n/a

 12-31-2003
(E-Mail Removed) (Richard Bos) writes:

> (E-Mail Removed) (ozbear) wrote:
>
> > My question would equally apply, I think, to something like...
> >
> > x = y = (y+y2)/2; /* ok, not ok, or bad analogy? */

>
> An additional point: it may seem that this causes undefined behaviour,
> because
>
> - a new value is computed for y (involving y, but that part is OK);
> - the value of y is then assigned to x, without an intervening
> sequence point.
>
> However, this is not what happens.

Even if it does, it's not UB according to 6.5#2. It's not forbitten to
modify two distinct objects without intervening sequence point, only to
modify the same object more than once.

> _This_ is:
>
> - a new value is computed for y (involving the old y in an OK manner);
> - that same _value_ is also the value of the assignment _expression_,
> which is then assigned to x.
>
> IOW, the evaluation of the inner assignment expression does not, in the
> abstract machine, read y again; it evaluates its right hand side, and
> then _both_ assigns this to y _and_ passes it on to the outer
> assignment.

Does the standard really guarantee that `y' is only read once in the
abstract machine? (C&V?) Why would it be a problem if the abstract machine
first stored the new value of `y', then read that same value again and
stored it in `x'?

The rules (6.5#2) don't forbit that an object is read an arbitrary number
of times between two sequence points, as long as it is only /modified/
once and only read to determine its new value. For example, I think in
this statement (which has defined behavior)

i = i + i + i + i + i;

the abstract machine would be allowed to read the value of `i' five times.

Martin

Joona I Palaste
Guest
Posts: n/a

 12-31-2003
Martin Dickopp <(E-Mail Removed)> scribbled the following:
> (E-Mail Removed) (Richard Bos) writes:
>> (E-Mail Removed) (ozbear) wrote:
>> > My question would equally apply, I think, to something like...
>> >
>> > x = y = (y+y2)/2; /* ok, not ok, or bad analogy? */

>>
>> An additional point: it may seem that this causes undefined behaviour,
>> because
>>
>> - a new value is computed for y (involving y, but that part is OK);
>> - the value of y is then assigned to x, without an intervening
>> sequence point.
>>
>> However, this is not what happens.

> Even if it does, it's not UB according to 6.5#2. It's not forbitten to
> modify two distinct objects without intervening sequence point, only to
> modify the same object more than once.

And to use the old value for anything other than computing the new
value.

--
/-- Joona Palaste ((E-Mail Removed)) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"And according to Occam's Toothbrush, we only need to optimise the most frequent
instructions."
- Teemu Kerola

Thomas Stegen
Guest
Posts: n/a

 12-31-2003
Martin Dickopp wrote:
>
> (1) The value of the object may be modified at most once.
> (2) If the value of the object is modified at all, the previous value
> may be used only to determine the new value.
>
> The standard gives two examples of undefined behavior:
>
> i = ++i + 1; violates (1), because the value of `i' is modified
> twice.
> a[i++] = i; violates (2). While `i' is modified only once, its
> previous value is used to determine its storage
> location (as opposed to its new value).
>

a[++i] = i;

The standard states that the previous value can only be *read* to
determine the value to be stored. Isn't it questionable wether or
not the previous value (as in the value just before this statement)
is read twice or once? Maybe we are looking at unspecified behaviour
since it depends on exactly when i is incremented and the order
of evaluation.

--
Thomas.