Evy Lino
Evy Lino

Reputation: 19

C++ function call by reference and return wasn't as expected.

I wrote a simple function as follows...

int fun(int *i, int *j) 
{  
     *i += 3; 
     *j += *i; 
     return (*i + *i); 
}

And in the main function I called the function as follows...

int main()
{
    int x = 3, y = 2, a, b; 
    a = x + y + fun(&x, &y) + x; 
    b = y + fun(&x, &y) + y;

    cout<<" a = " << a << "\n";
    cout<<" b = " << b << "\n";

}

Now the Question is the output wasn't as expected

After running this was the output

a=23
b=52

I was expecting

a=23 
b=46

I don't know exactly if anyone could explain.

Upvotes: 0

Views: 136

Answers (3)

Andy Prowl
Andy Prowl

Reputation: 126562

The result of evaluating your expression is unspecified, since the evaluations of x and fun(&x, &y) are indeterminately sequenced.

Notice, that an expression evaluation being allowed to yield an unspecified result does not mean that your program has undefined behavior; rather, it means that you cannot tell which of a finite set of possible results will be produced by the evaluation of that expression.

Interpreting the Standard can be quite tricky here (and in fact, in the original answer I interpreted it the wrong way - thanks to Jerry Coffin for noticing).

To see why this can be tricky, let's consider the first part of paragraph 1.9/15 of the C++11 Standard:

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

For example, given an expression which consists in computing the sum of two sub-expressions, such as (considering operator + is not overloaded here):

e1 + e2

Where the evaluation of e1 uses the value of a certain scalar s, and the evaluation of e2 has side-effects on that value, the behavior is undefined. For instance, the evaluation of:

(i + i++)

Gives undefined behavior because of the sentence quoted above.

However, your situation is different. The same paragraph later on specifies:

When calling a function (whether or not the function is inline), [...] Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.

This means that if the expression to be evaluated looks like this:

i + f(i)

And f(i) increments i, the behavior is no more undefined, but only unspecified. In other words, your compiler is allowed to evaluate i and f(i) in any order, but the possible outcome is just the result of one of these possible evaluations.

If the behavior were undefined, on the other hand, the possible outcome would have been anything (ranging from crashing, to behaving as you expected, to printing weird messages on the console, and so on and so on).

Upvotes: 5

Deepu
Deepu

Reputation: 7610

Consider the code given below,

x=10;
val=x+f(&x);


void f(int *a)
{
  *a=*a+10;
}

It is not defined by the C++ standard whether the left side of an operand will be evaluated first or the right side. So the value in variable val will be 30 if the left side is evaluated first and the value will be 40 if the right side is evaluated first. The same thing happens in your code also.

Upvotes: 1

Jerry Coffin
Jerry Coffin

Reputation: 490768

Your code has unspecified results.

The order of evaluation of the sub-expressions within an expression is not specified. Therefore, in x + y + fun(&x, &y) + x;, the x values you get outside the function call could be the values of x from before the function call, or after the function call. Since you have x at two different places outside it, one could be from before the function call and one from after -- or both could be from before or both could be from after.

There is a sequence point before entering a function, and before leaving a function, so there is a sequence point between using the value of x outside the function, and modifying its value inside the function. Therefore, your behavior is defined, but unspecified.

As of C++11, the "sequence point" terminology has been removed from the standard in favor of terminology like "sequenced before", "sequenced after" or "unsequenced with respect to". In the process, order has been specified in a few places that it wasn't previously. I don't believe any sequencing that was previously specified (such as the sequence points at entry to and exit from a function) have been removed. In other words, unless I'm completely mistaken, it doesn't change the situation in this case.

Upvotes: 1

Related Questions