19

I came across this rather vague behavior when messing around with code , here's the example :

#include <iostream>

using namespace std;


int print(void);

int main(void)
{
    cout << "The Lucky " << print() << endl;     //This line
    return 0;
}

int print(void)
{
    cout << "No : ";
    return 3;
}

In my code, the statement with comment //This lineis supposed to print out The Lucky No : 3, but instead it was printed No : The Lucky 3. What causes this behavior? Does this have to do with C++ standard or its behavior vary from one compiler to another?

user229044
  • 232,980
  • 40
  • 330
  • 338
caramel1995
  • 2,968
  • 10
  • 44
  • 57
  • 2
    Why do you believe that your expectation instead of the actual outcome is the more logical one? Can you explain your reasoning? – stakx - no longer contributing Jul 22 '12 at 20:55
  • 3
    Sidenote: Your `print` function is a nice example of a function with side-effects. Besides calculating a return value, it also changes global program state. Such functions are usually more difficult to reason about. Generally, strive towards functions that either compute a value *or* change state, but not both simultaneously. – stakx - no longer contributing Jul 22 '12 at 21:04

3 Answers3

18

The order of evaluation of arguments to a function is unspecified. Your line looks like this to the compiler:

operator<<(operator<<(operator<<(cout, "The Lucky "), print()), endl);

The primary call in the statement is the one with endl as an argument. It is unspecified whether the second argument, endl, is evaluated first or the larger sub-expression:

operator<<(operator<<(cout, "The Lucky "), print())

And breaking that one down, it is unspecified whether the function print() is called first, or the sub-expression:

operator<<(cout, "The Lucky ")

So, to answer your question:

What causes this behavior? Does this has to do with C++ standard or its behavior vary from one compiler to another?

It could vary from compiler to compiler.

Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
  • That's totally possible, and I might begin to see it ;) – atamanroman Jul 22 '12 at 21:07
  • @atamanroman: In the following expression: `operator<<(operator<<(cout, "The Lucky "), print())` What do you think should happen first, **This:** `operator<<(cout, "The Lucky ")`, or **this:** `print()`? Justify your answer. – Benjamin Lindley Jul 22 '12 at 21:10
  • I know, It's not defined and I get it know. So cout << "The lucky " + print() would be well defined? Deleted my answer (+1). – atamanroman Jul 22 '12 at 21:14
  • 1
    @atamanroman: Just for the sake of preciseness, you might want to be aware that there's a difference between "undefined" and "unspecified" behaviour. Roughly speaking, undefined behaviour means that anything can happen; unspecified behaviour means that what happens depends on the implementation (but implementations are not required to document what they do). – Stuart Golodetz Jul 22 '12 at 21:31
  • 1
    @atamanroman: the behavior isn't undefined, it's unspecified -- there's a difference. The compiler is free to evaluate the parameters in whatever order (including a random order) that it finds best, it's not free to not evaluate a parameter at all or to blow up your toaster. – jmoreno Jul 22 '12 at 21:35
  • 1
    @atamanroman: `cout << "The lucky" + print()` would output `No : lucky`. – molbdnilo Jul 23 '12 at 12:16
  • @BenjaminLindley Can you please also explain how the statments translated to 'operator<<(operator<<(operator<<(cout, "The Lucky "), print()), endl); ' – Dexters Oct 03 '13 at 04:32
4

Let's call the operator << simply operator .

Now we can write

cout << "The Lucky"

as

operator(cout, "The Lucky")

The result of this operation is cout, and it is passed to next <<, so we can write

operator(operator(cout, "The Lucky"), print() )

It is a function invocation with two parameters, and the standard doesn't say anything about the order of their evaluation.

So with some compilers you really may get

The Lucky No : 3
WendiKidd
  • 4,333
  • 4
  • 33
  • 50
Adam Trhon
  • 2,915
  • 1
  • 20
  • 51
0

In my compiler No: The Lucky 3 is the output.... it means that its behaviour varies from compiler to compiler.