4

Possible Duplicate:
Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)

I'm not able to understand the output of this program (using gcc).

main()
{
  int a=10;
  printf("%d %d %d\n",++a, a++,a);
}

Output:

12 10 12

Also, please explain the order of evaluation of arguments of printf().

Community
  • 1
  • 1
nowonder
  • 335
  • 2
  • 3
  • 14
  • 13
    when you post homework, which is ok, at least show that you have made your own attempt to solve the riddle before posting it to SO. just share your thoughts so far. everything else is just too blatantly lazy. – markus Aug 13 '09 at 06:38
  • Then read more... and proper documents: 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. – Anonymous Aug 13 '09 at 06:43
  • Evaluation is not guaranteed to be done right to left in printf. – Pavel Minaev Aug 13 '09 at 06:44
  • 3
    Duplicate of http://stackoverflow.com/questions/376278/parameter-evaluation-order-before-a-function-calling-in-c – Drew Hoskins Aug 13 '09 at 06:45

3 Answers3

10

The compiler will evaluate printf's arguments in whatever order it happens to feel like at the time. It could be an optimization thing, but there's no guarantee: the order they are evaluated isn't specified by the standard, nor is it implementation defined. There's no way of knowing.

But what is specified by the standard, is that modifying the same variable twice in one operation is undefined behavior; ISO C++03, 5[expr]/4:

Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.

printf("%d %d %d\n",++a, a++,a); could do a number of things; work how you expected it, or work in ways you could never understand.

You shouldn't write code like this.

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
Carson Myers
  • 37,678
  • 39
  • 126
  • 176
  • 1
    Actually, order is unspecified, not implementation defined. The difference is that the compiler documentation must define what happens in implementation-defined cases, but not in unspecified cases. – Steve Jessop Aug 13 '09 at 11:12
  • Ah, alright--will update the answer then – Carson Myers Aug 13 '09 at 20:08
  • @Steve Jessop: and if the compiler documentation defines the implementation-defined behavior to be unspecified? – Stephen Canon Feb 24 '10 at 05:31
  • @Stephen Canon: then the implementation does not conform to the standard (1.3.5). Documenting something to be "not documented" is meaningless, and writing the words "this could do anything" isn't documenting the behaviour! I'm sure you could argue that a compiler which ships with source is self-documenting, though, and in any case I doubt anyone will ever be taken to court over whether their C++ implementation conforms. – Steve Jessop Feb 25 '10 at 00:10
6

AFAIK there is no defined order of evaluation for the arguments of a function call, and the results might vary for each compiler. In this instance I can guess the middle argument was first evaluated, following by the first, and the third.

haggai_e
  • 4,689
  • 1
  • 24
  • 37
  • 2
    Yes, it's a common mistake to rely on any given order of evaluation. It works today with this compiler, then it stops working on another compiler. – sharptooth Aug 13 '09 at 06:40
  • But I have read that evaluation is done right to left in printf. Then why this problem. – nowonder Aug 13 '09 at 06:41
  • 1
    The order is unspecified, but modifying the same lvalue twice in the same expression (without a sequence point in between) is actually undefined behavior, and can thus do anything at all - including crash. – Pavel Minaev Aug 13 '09 at 06:42
  • But comma operator is a sequence point. – nowonder Aug 13 '09 at 06:43
  • 7
    Comma separating arguments in a function call is not a comma operator, it's just a part of syntax: `foo(a, b)` - this is not a comma operator; `x = a, b` - this is a comma operator. – Pavel Minaev Aug 13 '09 at 06:45
  • 1
    printf has no control over in which order its parameters are evaluated, that's up to the compiler. printf is just a random function. – Drew Hoskins Aug 13 '09 at 06:46
  • @Pavel: That poses the following question: if instead do `func((a++,0), (a++,0))` do I get an unspecifed result but no undefined behaviour? – caf Aug 13 '09 at 07:06
  • @caf I guess your example is the same as (a+=2,func(0,0)) so the result will be defined. – fortran Aug 13 '09 at 07:14
  • I think in that case there's still no defined order between the two `a++` sub-expressions. Each is defined to be evaluated before its corresponding `0`, but nothing with respect to each other. So I think that a valid order of evaluation is `a++`, `a++`, `0`, `0`, comma-operator, comma-operator, `func`. If I'm right and that's a valid order, then the result of the expression is undefined. – Steve Jessop Aug 13 '09 at 11:10
  • @onebyone, no, you're actually wrong here. Comma operator introduces a sequence point, and sequence point is defined thus in ISO C++: "Evaluation of an expression might produce side effects. At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place". So the relative order of `++` in this example will be guaranteed. Furthermore, since side effects are also guaranteed to be ordered, the result is well-specified and not unspecified. – Pavel Minaev Aug 13 '09 at 20:18
  • @Pavel: I don't think it's well-specified because of that. All the comma operator (or any sequence point) guarantees is that all the side effects are resolved. Therefore, it could evaluate a++, a++, and then hit one of the commas and clean up, meaning that the a++s could be in either order or interleaved. – David Thornley Aug 13 '09 at 20:34
0

As haggai_e hinted, the parameters are evalueted in this order: middle, left, right. To fully understand why these particular numbers are showing up, you have to understand how the increment works.

a++ means "do something with a, and then increment it afterwards". ++a means "increment a first, then do something with the new value".

In your particular Example, printf evaluates a++ first, reads 10 and prints it and only then increments it to 11. printf then evaluates ++a, increments it first, reads 12 and prints it out. The last variable printf evaluates is read as it is (12) and is printed without any change.

Although they are evaluated in a random order, they are displayed in the order you mentioned them. That's why you get 12 10 12 and not 10 12 12.

Mike
  • 2,567
  • 3
  • 23
  • 35
  • Yes... and the same way you can explain other possible outputs: 11 11 12 12 11 12 12 10 10 and so on... But what's the point? It's sufficient to know the rules for the evaluation order (not guaranteed) and the working of increment. – Anonymous Aug 13 '09 at 07:05
  • I was explaining the output since that was the askers problem. Every combustion Engine works the same but you still need one type of Engine to better understand the inner workings of every combustion Engine. Now substitute Engine by Example and combustion by printf and there you have my point. – Mike Aug 13 '09 at 07:24
  • 3
    Except that you're assuming too much regularity. The use of a++ and a++ without an intervening sequence point is undefined. Behavior like you describe is unspecified. There is no way you can explain what happens in a standard-conforming way, only what one particular implementation happened to do. – David Thornley Aug 13 '09 at 20:37