# sequence point and reference

16 views

### Lee

Feb 28, 2004, 7:17:06 AM2/28/04
to
Hello, everybody,

I have a midterm question as follows, which I believe is UB. I think the statement
k=j*f(i,j) is similar to j*(--j), which leads to undefined behaviour (UB).
But our professor insists the only correct result is 4. Any comments?

int f(int i, int j)
{
if(j==1)
return i;
--j;
++i;
return k=j*f(i, j);
}

int main()
{
int n=4;
cout<<f(1,n)<<endl;
return 0;
}

Thanks,

Lee

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

### Lee

Feb 28, 2004, 7:22:34 AM2/28/04
to
mistake, please accept my apology. The typo confues everybody.

{We have nine moderators, nonetheless both your posts arrived at me but
lacking a time machine... If you want to kill an earlier post always
email the moderators with the tracking number with a request for it to
be rejected.

I am adding this comment because others sometimes face the same problem.
-mod}

My question should be as follows:

**********************************************************************
Hello, everybody,

I have a midterm question as follows, which I believe is UB. I think

the statement j*f(i,j) is similar to j*(--j), which leads to undefined
behaviour (UB).

But our professor insists the only correct result is 4. Any comments?

int f(int i, int& j)

{
if(j==1)
return i;
--j;
++i;

return j*f(i, j);

### Dhruv Matani

Feb 28, 2004, 9:56:46 PM2/28/04
to
On Sat, 28 Feb 2004 07:22:34 -0500, Lee wrote:

> I have a midterm question as follows, which I believe is UB. I think
> the statement j*f(i,j) is similar to j*(--j), which leads to undefined
> behaviour (UB).
>
> But our professor insists the only correct result is 4. Any comments?

Looking at the code below, I can almost hear the UB coming out!
Yes. Even I think that the code below produces results that are not
defined correctly.

The value of 'j' may be cached before each call to f() and also it may not
be (as your professor is assuming it is).

> int f(int i, int& j)
> {
> if(j==1)
> return i;
> --j;
> ++i;
> return j*f(i, j);
> }
>
> int main()
> {
> int n=4;
> cout<<f(1,n)<<endl;
> return 0;
> }

I don't know what cout<< will print after all the functions return.
I believe that this produces multiple UBs!

--
Regards,
-Dhruv.

Proud to be a Vegetarian.
http://www.vegetarianstarterkit.com/
http://www.vegkids.com/vegkids/index.html

### Roger Orr

Feb 28, 2004, 9:58:41 PM2/28/04
to
Hi Lee,
"return j * f(i,j)" is similar to "return j * (--j )", but different enough
to remove the UB.

The difference is that, when calling a function, "there is also a sequence
point after the copying of a returned value and before the execution of any
expressions outside the function" (1.9p17 in the standard)

This means that the code is executed a bit like this:
int seqpt = f(i,j);
return j*seqpt;

The presence of the additional sequence point removes the ambiguity.

Roger Orr
--
MVP in C++ at www.brainbench.com

### John Potter

Feb 28, 2004, 10:33:24 PM2/28/04
to
On 28 Feb 2004 07:22:34 -0500, grace...@yahoo.com (Lee) wrote:

> I have a midterm question as follows, which I believe is UB. I think
> the statement j*f(i,j) is similar to j*(--j), which leads to undefined
> behaviour (UB).

The second is undefined because it modifies j and uses j without a
sequence point. The first does not have that problem because there is
a sequence point between evaluating the parameters to f and calling f
and another one between setting the return value of f and using it in
the caller. There is no undefined behavior in the example.

> But our professor insists the only correct result is 4. Any comments?

Never trust a professor, including me. :)

> int f(int i, int& j)
> {
> if(j==1)
> return i;
> --j;
> ++i;
> return j*f(i, j);

This is the point of contention. There is an lvalue to rvalue
conversion on i to send that parameter which is no problem. There
is no conversion on j to send the reference which is no problem.
There is an lvalue to rvalue conversion on j which is the problem.
The order in which the subexpressions of the multiplication are
evaluated is unspecified. The lvalue to rvalue conversion on j
may be performed before or after the call of f. There is not even
any requirement that it be done in the same order each time that
the function is called. The following valid translation of that code
is interesting.

int k(j);
int r(f(i, j));
return (rand() % 2 ? j : k) * r;

The possible results are 4, 8, 12, 24. Note that this is unspecified
behavior not undefined behavior. There are no other possible results.
With undefined behavior, anything can happen.

John

### Francis Glassborow

Feb 28, 2004, 10:36:11 PM2/28/04
to
<grace...@yahoo.com> writes

>mistake, please accept my apology. The typo confues everybody.
>
>{We have nine moderators, nonetheless both your posts arrived at me but
>lacking a time machine... If you want to kill an earlier post always
>email the moderators with the tracking number with a request for it to
>be rejected.
>
>I am adding this comment because others sometimes face the same problem.
>-mod}
>
>My question should be as follows:
>
>**********************************************************************
>Hello, everybody,
>
>I have a midterm question as follows, which I believe is UB. I think
>the statement j*f(i,j) is similar to j*(--j), which leads to undefined
>behaviour (UB).
>
>But our professor insists the only correct result is 4. Any comments?

Your professor is right as regards UB (well apart from the horrible
code, but I guess that was to make a point). Nowhere is j written to so
the rules about reading in order to modify are not operative. The change
of j is safely encapsulated in a function and so protected by sequence
points.

I think the result is actually unspecified because the compiler is free
to evaluate f(i, j) either before or after evaluating j (and is allowed
but not required to re-read j for the two occurrences.

>
>int f(int i, int& j)

It might have been more consistent to have passed i by reference as well

>{
> if(j==1)
> return i;
> --j;
> ++i;
> return j*f(i, j);
>}
>
>int main()
>{
> int n=4;
> cout<<f(1,n)<<endl;
> return 0;
>}
>

f(1, 4) calls f(2, 3) calls f(3, 2) calls f(4, 1). That last returns 4
but what value is used for the first j in j*f(i, j) depends on when the
compiler evaluates it. If, as it is entitled to do, it evaluates it
before calling the function you will get a different result from that
which you get if it evaluates it after the function returns. This is not
undefined behaviour (because the changes to j take place properly
protected by sequence points but it is unspecified behaviour because C++
(as well as C but not Java) does not lay down the order of evaluation.

For example,
f(1, 4) = 4*f(2,3) = 4*3*f(3,2) = 4*3*2*f(4, 1) = 4*3*2*4 is, I think,
perfectly consistent with the rules for evaluation in C++.

--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

### Francis Glassborow

Feb 29, 2004, 11:43:55 AM2/29/04
to
In message <pan.2004.02.28....@gmx.net>, Dhruv Matani
<dhru...@gmx.net> writes

>Looking at the code below, I can almost hear the UB coming out!
>Yes. Even I think that the code below produces results that are not
>defined correctly.

That is not the same as undefined. The code has unspecified behaviour,
but the compiler is not allowed to replace it with an implementation of
nethack. :-)

>
>The value of 'j' may be cached before each call to f() and also it may not
>be (as your professor is assuming it is).

Yes, that is why the result is unspecified.

>
>> int f(int i, int& j)
>> {
>> if(j==1)
>> return i;
>> --j;
>> ++i;
>> return j*f(i, j);
>> }
>>
>> int main()
>> {
>> int n=4;
>> cout<<f(1,n)<<endl;
>> return 0;
>> }
>
>I don't know what cout<< will print after all the functions return.
>I believe that this produces multiple UBs!

Then you believe wrong. There is no undefined behaviour in the above
code.

--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

### Carsten Hansen

Feb 29, 2004, 12:33:59 PM2/29/04
to

"Lee" <grace...@yahoo.com> wrote in message

The order in which the two terms in the expression

j * f(i,j)

are evaluated is unspecified. Hence the result of the calculation cannot be
determined.

Carsten Hansen

### Dhruv Matani

Mar 1, 2004, 12:11:37 PM3/1/04
to
On Sun, 29 Feb 2004 11:43:55 -0500, Francis Glassborow wrote:

> In message <pan.2004.02.28....@gmx.net>, Dhruv Matani
> <dhru...@gmx.net> writes
>>Looking at the code below, I can almost hear the UB coming out!
>>Yes. Even I think that the code below produces results that are not
>>defined correctly.
>
> That is not the same as undefined. The code has unspecified behaviour,
> but the compiler is not allowed to replace it with an implementation of
> nethack. :-)

Sorry! I agree I'm wrong here. I remember having this discussion about the
difference between UB and Defined B with Unspecified B.

However, form a programmer's point of view, I would only care about
whether the following would:
1. Compile.
2. Run.
3. Produce the same results always on different platforms or even different
versions of the same compiler or even the same compiler!

(3) Basically means not doing anything that is explicitly specified by the
standard to be UB or if the standard says that something is implementation
defined then I should try and not get tied by some particular
implementation.

>>The value of 'j' may be cached before each call to f() and also it may not
>>be (as your professor is assuming it is).
>
> Yes, that is why the result is unspecified.

Ok.

>>I don't know what cout<< will print after all the functions return.
>>I believe that this produces multiple UBs!
>
> Then you believe wrong. There is no undefined behaviour in the above
> code.

Then would multiple Unspecified Behaviours be the correct term to use?

--
Regards,
-Dhruv.