2

I've been staring at this for about an hour and I honestly have no idea what I'm missing.

#include <iostream>

using namespace std;

void callChain();

double chain(int, int &, int &);

int main()
{
    callChain();
}

void callChain() {
    int totalInches = 53;
    int feet;
    int inches;

    cout << "\nTesting chain for 53 inches: \nExpected result: 15.46 feet: 4 inches: 5" << endl;
    cout << "Actual result: " << chain(totalInches, feet, inches) << " feet: " << feet << " inches: " << inches << endl;
}

double chain(int totalInches, int &feet, int &inches) {
    feet = totalInches / 12;
    inches = totalInches % 12;

    return (feet) * 3.49 + (inches) * .30;
}

The return is correct, so obviously the function is working, but for the life of me I can't figure out why feet and inches aren't changing. Everything is spelled right, I have all my ampersands, but for some reason, the display is showing feet as 8 and inches as 7. I have no idea where those numbers are even coming from.

Bay Conner
  • 41
  • 4
  • 4
    The order things happens in your output is not specified. You don't know in which order the `feet`, `inches` and the `chain()` function call will be evaluated. – Some programmer dude Mar 05 '18 at 08:35
  • Check this question and its answers: https://stackoverflow.com/q/8931249/5958455 – iBug Mar 05 '18 at 08:37
  • And just to show how indeterminate things can be, I pasted your code verbatim into jdoodle for g++ 14 GCC 7.20 at got the answers you expected to have. :) – Ray Toal Mar 05 '18 at 08:37

3 Answers3

5

Remember that << is syntatic sugar for a function call and the order of evaluation of these functions is not necessarily in the order that you think it is. In fact C++ doesn't actually specify the order. So the final parts of you second cout are printing out the starting values of feet and inches.

Call chain(totalInches, feet, inches) in an intermediate step before the second cout, perhaps even in this way (Acknowledge @DavidSchwartz):

cout << "Actual result: " << chain(totalInches, feet, inches);
cout << " feet: " << feet << " inches: " << inches << endl;
Bathsheba
  • 220,365
  • 33
  • 331
  • 451
  • Or just: `cout << "Actual result: " << chain(totalInches, feet, inches); cout << " feet: " << feet << " inches: " << inches << endl;` – David Schwartz Mar 05 '18 at 08:37
1

The evaluation order is unspecified in the ISO C++ standard, according to ostream chaining, output order

To ensure the function is called before those variables are accessed, separate the output chain:

cout << "Actual result: " << chain(totalInches, feet, inches);
cout << " feet: " << feet << " inches: " << inches << endl;
iBug
  • 30,581
  • 7
  • 64
  • 105
  • Since C++17, the evaluation order is strictly from left to right. I have also added a late answer to the question you linked. – xskxzr Mar 05 '18 at 12:15
0

Just for better illustration of the answers given so far (giving some more details):

std::cout << x is syntactic sugar for operator<<(std::cout, x); as operator<< returns its first argument, std::cout << x << y; gets:

operator<<(operator<<(std::cout, x), y);

Obviously, the first argument to the outer call will be evaluated (e. g. the inner call executed) before the the outer call actually is performed – and this is where any guarantees already end, i. e. as order of argument evaluation is unspecified, the compiler is quite well allowed to evaluate y before the call to the inner operator – including the evaluation of the latter's arguments!

operator<<(operator<<(std::cout, f(x)), x);

Similarly now, the only guarantees here are that f(x) is called before the inner operator is called and the inner operator being called before the outer one; still, the raw x can be evaluated at very first...

Obviously, your compiler starts evaluating the arguments from last to first, most likely due to the calling convention in use (quite likely cdecl; on Windows possibly stdcall)...

The change in the accepted answer introduces a sequence point between the function calls (old, pre-C++11 wording), which ensures that all effects of the previous call are completed before the call to the next function, i. e. (using new C++11 wording):

operator<<(std::cout, f(x)); // is sequenced  b e f o r e  next line
operator<<(std::cout, x);    // is sequenced  a f t e r  previous line
Aconcagua
  • 19,952
  • 4
  • 31
  • 51