3

I don't understand what is passed to the function f() when I call it like this.

main()
{
  void f(int,int);
  int i=10;
  f(i,i++);
}

void f(int i,int j)
{ printf("%d %d",i,j); }

gives me 11 10 .Can somebody explain why its 11?

11
  • 7
    Try it and find out :) May 28, 2012 at 18:02
  • I did that, but I need an explanation
    – nischayn22
    May 28, 2012 at 18:02
  • 2
    @nischayn22: Can you post the results and explaint he part you don't understand? Also, have you tried f(i,++i); and compared it to f(i,i++);? May 28, 2012 at 18:03
  • 1
    @FrustratedWithFormsDesigner I did that, it gives me 11 11 in first case and 11 10 in second..But I don't get why the first parameter is 11
    – nischayn22
    May 28, 2012 at 18:11
  • Eu! Why would you feel compelled to write this sort of thing? May 29, 2012 at 1:55

3 Answers 3

5

The behavior is undefined, as follows:

From the C99 standard:

6.5 Expressions
...
2 Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression.72) Furthermore, the prior value shall be read only to determine the value to be stored.73)
72) A floating-point status flag is not an object and can be set more than once within an expression.
73) This paragraph renders undefined statement expressions such as

    i = ++i + 1;
    a[i++] = i;
while allowing

    i = i + 1;
    a[i] = i;

We're violating the second sentence of that paragraph; we're not just reading the prior value to determine the new value to be stored.

Note that undefined doesn't necessarily mean illegal. Undefined simply means that the compiler is free to handle the situation any way it sees fit; any result is considered "correct". You could very well wind up with the result you expected. Or not. The program could crash. Or not. Or anything else could happen.

In this case, you will get different results based on platform, compiler, optimization settings, surrounding code, etc. The reason for that is as follows:

6.5.2.2 Function calls
...
10 The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.

It is unspecified whether i or i++ is evaluated first; furthermore, it is unspecified whether the side effect of ++ is applied immediately after i++ is evaluated, as follows:

6.5.2.4 Postfix increment and decrement operators
...
2 The result of the postfix ++ operator is the value of the operand. After the result is obtained, the value of the operand is incremented. (That is, the value 1 of the appropriate type is added to it.) See the discussions of additive operators and compound assignment for information on constraints, types, and conversions and the effects of operations on pointers. The side effect of updating the stored value of the operand shall occur between the previous and the next sequence point.

Emphasis mine.

Edit

Changed the wording a bit to make it clear that the behavior is undefined.

3
  • Your middle paragraph says unspecified, but your first says undefined. Which is it?
    – Pubby
    May 29, 2012 at 10:02
  • Since the order of evaluations and side effects are unspecified, you will get different results under different circumstances. The behavior is left undefined so that compilers aren't required to do anything in particular when they encounter code like that. This case would be easy enough to detect and issue a diagnostic against, but what about a case like f(*a, (*b)++); where both a and b are set to point to i? In a different translation unit?
    – John Bode
    May 29, 2012 at 11:06
  • @Pubby Both. If a variable gets a value stored anywhere in an expression, one is not allowed to read the same variable elsewhere in that same expression for any other purposes than to determine the value to store. Since the OP's code did this, it is invoking undefined behavior (meaning anything can happen). But on top of that, the order of evaluation of function parameters is unspecified behavior, meaning that the order of the evaluation will be either left-side or right-side first and the compiler does not need to document or tell us which one that applies.
    – user29079
    Jun 1, 2012 at 13:37
7

Because undefined behaviour, that's why. You read the value twice and modify it once with no intervening sequence point, which is a giant pile of illegal. Even if it were not illegal, the compiler has no obligation to evaluate your function arguments in any particular order, or indeed, to even evaluate one fully before evaluating another.

8
  • Is this really UB? I thought it was only UB if it was modified twice without a sequence point. (either way you can't rely on the output)
    – Pubby
    May 28, 2012 at 18:16
  • 1
    It's the order of operations that is undefined. The compiler can choose to evaluate i either before or after i++. May 28, 2012 at 20:25
  • @Pubby: today (C++11) it's called sequenced-before/sequenced-after. The evaluation of the first argument is sequenced neither or after the second. The result is still the same here: UB.
    – MSalters
    May 28, 2012 at 21:13
  • 2
    @Steven: That would be unspecified, not undefined. In particular, it means that foo(bar(), baz()); is perfectly well defined, but may call either bar or baz first.
    – MSalters
    May 28, 2012 at 21:15
  • Sorry, yeah, you're right. May 28, 2012 at 21:25
3

The order of evaluation of function arguments is unspecified and so 11 10 is a correct possible output.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.