2

Possible Duplicate:
Compilers and argument order of evaluation in C++
cout << order of call to functions it prints?

  1. This:

    int k=3;
    printf("%d %d %d",k++,k,++k);
    

    Gives output as 4 4 4 because they are pushed into the stack as:

    %d%d%d
    
    4  -- for k++    
    4  --for k    
    4  --for ++k
    

    Right?

  2. This:

    int k = 3;
    cout << k++ << k << ++k;
    

    Is actually repeated function calls, so it's equivalent to:

    ( ( (cout << k++) << k) << ++k);
    

    So, I suppose first of all k++ then k and then ++k must always be executed in this order, right? I believe a function call is a sequence point, but the outputs vary on different implementations. Why is this so?

Community
  • 1
  • 1
nikel
  • 2,856
  • 8
  • 34
  • 67

4 Answers4

7

The order of evaluation of arguments is unspecified by the standards. That means, it can happen in any order the implementation wants to.

AraK
  • 87,541
  • 35
  • 171
  • 230
  • 6
    No, the behavior is undefined. That's much worse than having unspecified order. If it were just that order were unspecified, there would be a finite number of possible outputs for this program. But since `k` is modified more than once between sequence points, UB is invoked, and **anything** could happen. Including ASCII art of monkeys getting printed on stdout, or all your files getting deleted. – R.. GitHub STOP HELPING ICE Sep 09 '11 at 02:10
  • That's true sir. I should have clarified that the unspecified behavior results in an undefined behavior in the case of printf. In contrast, the second case is an example of implementation defined behavior only as @Chris Lutz clarified in a comment on other answer. – AraK Sep 09 '11 at 02:15
  • I'm not sure if Chris is right. See Benjamin's comment... – R.. GitHub STOP HELPING ICE Sep 09 '11 at 02:20
4

This is undefined because there is no sequence point between the , in the printf statement. Without a sequence point the compiler is free to order writes to the memory location k as it wills.

Now you may be wondering 'what the hell is a seqeunce point' and why is it relevant? Basically a sequence point is a point in the code where the memory location in question, in this case k has been modified at most once. There is a fuller description here:https://isocpp.org/wiki/faq/misc-technical-issues#double-mod-betw-seq-pt

As you can see from the FAQ, the , in the printf does not introduce a sequence point.

In the case of cout this is different because there are 3 function calls to operator >>. A function call introduces a sequence point therefore the modifications to memory location k have a defined order. However (and this was a point I missed but Cubbi pointed out) because C/C++ doesn't define the order of evaluation of function arguments those arguments, even if they are functions, can be evaluated in any order the compiler defines. So in the expression:

f(h(), g())

Whether h() or g() is evaluated first is undefined: http://www.stroustrup.com/bs_faq2.html#undefined. So this is the reason why even in the case of cout you are getting different results from different compilers, basically because the cout << k++ << k << ++k translates to cout.operator<<(k++).operator<<(k).operator(++k) which is effectively an expression like this: f(h(g(cout, k++), k), ++k) and each function argument is evaluated in an unspecified order.

jdhao
  • 13,374
  • 7
  • 87
  • 151
sashang
  • 10,408
  • 4
  • 39
  • 53
2

You've got answers that cover the call to printf but you're also asking why does the output of the cout statement vary between compilers.

You're correct to say that it is equivalent to

( ( (cout<<k++)<<k)<<++k);

now, to evaluate that expression and obtain its result, the compiler must evaluate the rightmost <<. Before the function call to that << can be made, its two operands, ( (cout<<k++)<<k) and ++k must be evaluated. And those two evaluations can occur in any order, or even simultaneously (compilers often interleave cpu instructions from two independent (as the compiler thinks) branches of code. And since the evaluation of both expressions involves writing to k, the behavior is undefined in case of the cout as well.

Cubbi
  • 43,318
  • 13
  • 94
  • 159
  • No it's not undefined in the case of cout becuase those are 3 function calls and each function call introduces a sequence point between it and the next call. – sashang Sep 09 '11 at 02:18
  • @sashang when evaluating `f(a, b)`, evaluation of `a` and evaluation of `b` are unsequenced, regardless of how inner subexpressions of `a` are sequenced between each other. – Cubbi Sep 09 '11 at 02:23
0

Actually, both printf and cout << are function calls, and C++ as well as C do not define an evaluation order for arguments. So the result for these test cases would vary from compiler to compiler, since its implementation defined.

K-ballo
  • 76,488
  • 19
  • 144
  • 164
  • More on the subject: http://www2.research.att.com/~bs/bs_faq2.html#evaluation-order – K-ballo Sep 09 '11 at 02:00
  • 1
    Note that Unspecified and Implementation Defined are no the same in C++. Implementation defined means that the implementation should choose one and only one way and it should be documented, whereas Unspecified means that the implementation can choose one way for one case and choose another way in the next case in the same code. – AraK Sep 09 '11 at 02:01
  • I am aware of such difference, what's the case for evaluation order of function parameters then? – K-ballo Sep 09 '11 at 02:03
  • 2
    The `cout` version _is_ defined, because `operator< – Chris Lutz Sep 09 '11 at 02:05
  • 5
    @Chris: There are sequence points between the calls to `operator< – Benjamin Lindley Sep 09 '11 at 02:11
  • 1
    Indeed, since function arguments can be evaluated in any order, then in the outer call to `operator< – Ken Wayne VanderLinde Sep 09 '11 at 02:17