3
#include <iostream>
using namespace std;

int a = 8;

int g()
{
    a++; 
    return a - 1;
}

int f()
{
    a++;
    return a;
}

int main()
{
    cout << g() << " " << f() << " " << g() + f() << endl;
    system("PAUSE");
    return 0;
}

Output is "11 11 18"

Stuart Golodetz
  • 20,238
  • 4
  • 51
  • 80
Xiaolong
  • 239
  • 1
  • 3
  • 12
  • 1
    In the future, it might help to mention what output you were _expecting_. – Chris Frederick May 13 '11 at 14:05
  • 1
    This question is related to this [Is this code well-defined?](http://stackoverflow.com/questions/4709727/is-this-code-well-defined) ... and see the explanation by @Johannes. – Nawaz May 13 '11 at 14:16

6 Answers6

9

The order of evaluation of functions is unspecified in C++. In the code:

cout << g() << " " << f() << " " << g() + f() << endl;

The compiler could emit code to call f(), f(), g(), g() and then add the results. Or it could do something else.

This is nothing specific to use with cout, BTW - if you write code like this:

x = a() + b() * c();

There is no guarantee about which order a, b and c will be called in. This is one of the many reasons that global variables are A Bad Thing - you often cannot predict how functions that change them will be called.

  • +1: I was about to post this, but took too much time finding quote & verse from the Standard. – John Dibling May 13 '11 at 14:29
  • 2
    "The order of evaluation ... is not well-specified" The order of evaluation is explicitly unspecified in the standard. Formally, it may even vary dynamically, with a different order each time you execute the statement. Practically, it will vary according to compiler and the level of optimization you compile with. – James Kanze May 13 '11 at 14:34
  • @James: I think that's exactly what @Neil meant to say. – John Dibling May 13 '11 at 14:35
4

It has to do with order of evaluation. In this case g() + f() is evaluated first, thus giving 8 + 10 = 18. After this a == 10 and f() is evaluated which gives 11 and sets a to 11 etc

rtn
  • 127,556
  • 20
  • 111
  • 121
  • 2
    That's what appears to happen in this case, but C++ doesn't guarantee it to be so. –  May 13 '11 at 14:07
  • So it means that it follows right association rule for "<<", right? – Xiaolong May 13 '11 at 14:10
  • 1
    @user Wrong It is NOT DEFINED! –  May 13 '11 at 14:11
  • @user: It means that your particular compiler says its so, at least for now. The great thing about undefined behavior is it can change and cannot be relied upon. – Joe May 13 '11 at 14:11
  • @Joe Actually, the compiler could choose a different order next time the code was compiled, depending on its own internal state. –  May 13 '11 at 14:13
  • @Neil: Roger that. Edited my post. Thanks. – rtn May 13 '11 at 14:14
  • @Neil: Nit pick: It's not "not defined," it's "unspecified." The compiler decides, at it's pleasure, in which order to evaluate `g()`, `f()`, and `g()+f()`. – John Dibling May 13 '11 at 14:18
  • 2
    @Joe: It's not "undefined behavior" it is "unspecified behavior." There is a huge difference between the two. – John Dibling May 13 '11 at 14:19
  • @John I always get them mixed up. –  May 13 '11 at 14:20
  • 1
    @Neil, @Joe: "Undefined behavior" = malformed code, the compiler could do anything. "Unspecified behavior" = well-formed code, the compiler must do something deterministic, but no documentation of that behavior is required. – John Dibling May 13 '11 at 14:28
  • @John Yes, I know what they mean, its remembering when each is applicable I have trouble with :-) –  May 13 '11 at 14:35
4

For this particular result, g() + f() is being evaluated first which will result in a eventually being incremented to 10 and the result being 18. This is the case regardless of whether the g() or f() bit of that sum is done first. Doing g() first gives 8+10, otherwise it's 9+9.

Then f() is evaluated, setting a to 11 and returning 11.

Then g() is evaluated, setting a to 12 and returning 11.

In other words, it's calling the right-most bits of the cout first and proceeding left.

Now you'll notice the phrase "for this particular result" in my ramblings above. Whether this is mandated by the standard, I don't know for sure (meaning I couldn't be bothered looking it up at the moment), but I very much doubt it, based on experience.

So, while it's actually outputting the items in the correct order, the side effects can be different depending on a large number of things. That's one reason why global variables (or, more correctly, side effects on them) are rarely a good idea and you should probably rethink your use of them :-)

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    It's not defined, in either C or C++. –  May 13 '11 at 14:10
  • That is the problem, but are you sure this is a standard for every compiler? – Xiaolong May 13 '11 at 14:13
  • Thank you! I'll test it in other compiler to verify it! – Xiaolong May 13 '11 at 14:15
  • @user752501, testing it in another compiler will prove nothing! You need to be aware that the _standard_ is the only defining document, not what two (or even a hundred) implementations do. – paxdiablo May 13 '11 at 14:22
  • @Neil Butterworth "It's not defined" makes it sound like undefined behavior. There's no undefined behavior in his code, just unspecified behavior. – James Kanze May 13 '11 at 14:31
  • @James, yes John Dibling made this point already. I always get the two mixed up. I've changed my answer to reflect this but I can't edit old comments. –  May 13 '11 at 14:34
3

The order of execution is not guaranteed unless there is a sequence point in the expression. If you want to know the order here you have to break it into separate statements.

cout << g() << " ";
cout << f() << " ";
int temp = g();
temp += f();
cout << temp << endl;
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • +1 Thank you very much, I was so confused about this. I was sure () and << were read from left to right. Reading up on sequence point now. – flumpb May 13 '11 at 14:16
2

a is a global variable and thus is being accessed by all.
in addition, operator<< is being accessed from right to left, so:
g() + f() = 8+10=18 (a after it is 10)
f() = 11 and a is 11
g() = 11 and a is 12

amit
  • 175,853
  • 27
  • 231
  • 333
  • I believe the order of operation for things like this is actually undefined by the spec, so it could be L->R or R->L – Joe May 13 '11 at 14:05
0
cout << g() << " " << f() << " " << g() + f() << endl;

same as

cout.operator<<(operator<<(operator<<(operator<<(operator<<(operator<<(endl), g() + f()), " "), f()), " "), g());

The order the functions are called is why this occurs.

Jordonias
  • 5,778
  • 2
  • 21
  • 32
  • @Jordonias So we are all wrong? The order of function calls actually is specified in the C++ Standard? Great! Now please quote the bit in the standard that says this. –  May 13 '11 at 15:00
  • 1
    And to the upvoter, if you know zip about C++, don't vote on C++ answers. –  May 13 '11 at 15:04
  • @Neil Or you can go take a look at how to overload operator<< and what the parameters for the function are and how the << operator works. I'm not saying you're wrong I'm just giving the most literal explanation for all of the previous answers. Will you at least agree that cout << "Hello"; is equivalent to cout.operator("Hello"); – Jordonias May 13 '11 at 15:07
  • 1
    @Jordonias You are not explaining the answers and you are wrong. The order in which g() and f() are called in the users code is unspecified, simple as that. –  May 13 '11 at 15:10
  • 1
    To simplify, in `x( y( a(), b() ), c() )` y, a, b and c must be called before x, but that is all you can say. The order of calls of a, b and c are unspecified. –  May 13 '11 at 15:26