I'm a TA for an intro C++ class. The following question was asked on a test last week:
What is the output from the following program:
int myFunc(int &x) {
int temp = x * x * x;
x += 1;
return temp;
}
int main() {
int x = 2;
cout << myFunc(x) << endl << myFunc(x) << endl << myFunc(x) << endl;
}
The answer, to me and all my colleagues, is obviously:
8
27
64
But now several students have pointed out that when they run this in certain environments they actually get the opposite:
64
27
8
When I run it in my linux environment using gcc I get what I would expect. Using MinGW on my Windows machine I get what they're talking about.
It seems to be evaluating the last call to myFunc first, then the second call and then the first, then once it has all the results it outputs them in the normal order, starting with the first. But because the calls were made out of order the numbers are opposite.
It seems to me to be a compiler optimization, choosing to evaluate the function calls in the opposite order, but I don't really know why. My question is: are my assumptions correct? Is that what's going on in the background? Or is there something totally different? Also, I don't really understand why there would be a benefit to evaluating the functions backwards and then evaluating output forward. Output would have to be forward because of the way ostream works, but it seems like evaluation of the functions should be forward as well.
Thanks for your help!
The C++ standard does not define what order the subexpressions of a full expression are evaluated, except for certain operators which introduce an order (the comma operator, ternary operator, short-circuiting logical operators), and the fact that the expressions which make up the arguments/operands of a function/operator are all evaluated before the function/operator itself.
GCC is not obliged to explain to you (or me) why it wants to order them as it does. It might be a performance optimisation, it might be because the compiler code came out a few lines shorter and simpler that way, it might be because one of the mingw coders personally hates you, and wants to ensure that if you make assumptions that aren't guaranteed by the standard, your code goes wrong. Welcome to the world of open standards :-)
Edit to add: litb makes a point below about (un)defined behavior. The standard says that if you modify a variable multiple times in an expression, and if there exists a valid order of evaluation for that expression, such that the variable is modified multiple times without a sequence point in between, then the expression has undefined behavior. That doesn't apply here, because the variable is modified in the call to the function, and there's a sequence point at the start of any function call (even if the compiler inlines it). However, if you'd manually inlined the code:
std::cout << pow(x++,3) << endl << pow(x++,3) << endl << pow(x++,3) << endl;
Then that would be undefined behavior. In this code, it is valid for the compiler to evaluate all three "x++" subexpressions, then the three calls to pow, then start on the various calls to operator<<. Because this order is valid and has no sequence points separating the modification of x, the results are completely undefined. In your code snippet, only the order of execution is unspecified.
Exactly why does this have unspecified behaviour.
When I first looked at this example I felt that the behaviour was well defined because this expression is actually short hand for a set of function calls.
Consider this more basic example:
cout << f1() << f2();
This is expanded to a sequence of function calls, where the kind of calls depend on the operators being members or non-members:
// Option 1: Both are members
cout.operator<<(f1 ()).operator<< (f2 ());
// Option 2: Both are non members
operator<< ( operator<<(cout, f1 ()), f2 () );
// Option 3: First is a member, second non-member
operator<< ( cout.operator<<(f1 ()), f2 () );
// Option 4: First is a non-member, second is a member
cout.operator<<(f1 ()).operator<< (f2 ());
At the lowest level these will generate almost identical code so I will refer only to the first option from now.
There is a guarantee in the standard that the compiler must evaluate the arguments to each function call before the body of the function is entered. In this case, cout.operator<<(f1()) must be evaluated before operator<<(f2()) is, since the result of cout.operator<<(f1()) is required to call the other operator.
The unspecified behaviour kicks in because although the calls to the operators must be ordered there is no such requirement on their arguments. Therefore, the resulting order can be one of:
f2()
f1()
cout.operator<<(f1())
cout.operator<<(f1()).operator<<(f2());
Or:
f1()
f2()
cout.operator<<(f1())
cout.operator<<(f1()).operator<<(f2());
Or finally:
f1()
cout.operator<<(f1())
f2()
cout.operator<<(f1()).operator<<(f2());
The order in which function call parameters is evaluated is unspecified. In short, you shouldn't use arguments that have side-effects that affect the meaning and result of the statement.
Yeah, the order of evaluation of functional arguments is "Unspecified" according to the Standards.
Hence the outputs differ on different platforms
As has already been stated, you've wandered into the haunted forest of undefined behavior. To get what is expected every time you can either remove the side effects:
int myFunc(int &x) {
int temp = x * x * x;
return temp;
}
int main() {
int x = 2;
cout << myFunc(x) << endl << myFunc(x+1) << endl << myFunc(x+2) << endl;
//Note that you can't use the increment operator (++) here. It has
//side-effects so it will have the same problem
}
or break the function calls up into separate statements:
int myFunc(int &x) {
int temp = x * x * x;
x += 1;
return temp;
}
int main() {
int x = 2;
cout << myFunc(x) << endl;
cout << myFunc(x) << endl;
cout << myFunc(x) << endl;
}
The second version is probably better for a test, since it forces them to consider the side effects.
And this is why, every time you write a function with a side-effect, God kills a kitten!
Related
This question already has answers here:
Order of evaluation in C++ function parameters
(6 answers)
Warn about UB in argument evaluation order
(1 answer)
Closed 2 years ago.
I'm new at programming. This is part of my code:
double logic(double a,double b)
{
(Code Here...)
}
double inputDouble(double x)
{
std::cout << "Please, input a floating number: ";
std::cin >> x;
std::cout << std::endl;
return x;
}
int main()
{
double a,b;
std::cout << logic(inputDouble(a),inputDouble(b));
return 0;
}
I've noticed the problem on the compiler, them I've checked the debug windows and the problem that I'm having is that when I insert a value on 'a' by 'inputDouble' function, it goes to 'b', and vice-versa. So at the end of the program what I get in 'logic' function is: double a=b(From main()), double b=a(From main()). I hope and am grateful to someone who can explain to me what I'm doing wrong so the variables are being assigned on the wrong places. And I also apologize if there is any gramatical mistake on this post as english is not my first language.
The expression:
logic(inputDouble(a),inputDouble(b))
does not guarantee the order in which those calls to inputDouble() are made, just that they're both complete before the call to logic(). So it may call the a one first, or it may call the b one first(a).
To guarantee order, you can use something like:
double inputDouble() { // slight change, see below.
double x;
std::cout << "Please, input a floating number: ";
std::cin >> x;
std::cout << std::endl;
return x;
}
int main() {
double a = inputDouble(); // guarantee get 'a' first.
double b = inputDouble();
std::cout << logic(a, b);
return 0;
}
You could also use:
double a = inputDouble(); // guarantee get 'a' first.
std::cout << logic(a, inputDouble());
but I prefer the first one for consistency.
You'll notice a slight change to the inputDouble() function as well to remove the parameter, no useful purpose is served by passing the uninitialised values to the function, then over-writing and returning it.
Instead, I've just used a local variable to receive the value and return it.
A more robust program would also ensure that user input was valid but that can be left for a different question, since it almost certainly already exists on this site.
(a) For the language lawyers amongst us, this is covered in C++20 [expr.call] /8 (my emphasis):
The initialization of a parameter, including every associated value computation and side effect, is indeterminately sequenced with respect to that of any other parameter. [Note: All side effects of argument evaluations are sequenced before the function is entered].
In inline functions, the compiler is suggested to copy a piece of code at compile time into the caller program.
#include<iostream>
inline void swap(int *a, int *b){
a=a^b;
b=a^b;
a=a^b;
}
int main(){
int a=2,b=3;
swap(a,b);
std::cout<<a<<b;
return 0;
}
Here, the swap function is call by value.
So, suppose that the above code is inlined by the compiler, then will the actual variable a and b will be passed so that it works perfectly or the part that has an inline function has some other scope?
Because, if it is inlined, the code is directly copied into main here, and since no parameter passing will take place, the code have the access to a and b.
ps:The question has been edited because I was not able to precisely put in words my doubt so it has so may downvotes.
Why is it that the first code fails to work until a pointer to a and b are used?
Because swap takes pointers. You can't call it without pointers, even it it would be inlined. The program still needs to be syntactically correct even if the semantics change due to optimizations.
Also note that inline is just a suggestion to the compiler to inline the function. It's actual purpose is to prevent multiple definition errors if you define the function in multiple translation units.
In inline functions, the piece of code at compile time is copied into the caller program.
That's completely incorrect. Making a function inline has no effect on what your program does. If your function does not work without inline then it's not going to start working when you make it inline, and vice versa.
So the premise of the question is wrong.
Your inline function and usage are wrong. You are passing variables to a function that requires pointers.
In main, your function call should be:
swap(&a, &b);
If you don't want to mess with pointers, I recommend a version using references:
#include <iostream>
using std::cout;
inline void my_swap(int& a, int& b)
{
int temp = a;
a = b;
b = a;
}
int main()
{
int p = 42, q = 1;
cout << "p: " << p << ", q: " << q << "\n";
swap(p, q);
cout << "p: " << p << ", q: " << q << "\n";
return 0;
}
The parameters of swap are passed by reference which means that the function will modify the variables passed to swap.
Take the above main function and print out the assembly language. There should be no branch or call instructions to the swap function. Increment the optimization levels as necessary (some compilers won't inline the code at the lowest optimization levels, to make debugging easier). A very intelligent compiler may replace the entire function with an assembly language instruction for swapping.
Why is the output of the below program what it is?
#include <iostream>
using namespace std;
int main(){
cout << "2+3 = " <<
cout << 2 + 3 << endl;
}
produces
2+3 = 15
instead of the expected
2+3 = 5
This question has already gone multiple close/reopen cycles.
Before voting to close, please consider this meta discussion about this issue.
Whether intentionally or by accident, you have << at the end of the first output line, where you probably meant ;. So you essentially have
cout << "2+3 = "; // this, of course, prints "2+3 = "
cout << cout; // this prints "1"
cout << 2 + 3; // this prints "5"
cout << endl; // this finishes the line
So the question boils down to this: why does cout << cout; print "1"?
This turns out to be, perhaps surprisingly, subtle. std::cout, via its base class std::basic_ios, provides a certain type conversion operator that is intended to be used in boolean context, as in
while (cout) { PrintSomething(cout); }
This is a pretty poor example, as it's difficult to get output to fail - but std::basic_ios is actually a base class for both input and output streams, and for input it makes much more sense:
int value;
while (cin >> value) { DoSomethingWith(value); }
(gets out of the loop at end of stream, or when stream characters do not form a valid integer).
Now, the exact definition of this conversion operator has changed between C++03 and C++11 versions of the standard. In older versions, it was operator void*() const; (typically implemented as return fail() ? NULL : this;), while in newer it's explicit operator bool() const; (typically implemented simply as return !fail();). Both declarations work fine in a boolean context, but behave differently when (mis)used outside of such context.
In particular, under C++03 rules, cout << cout would be interpreted as cout << cout.operator void*() and print some address. Under C++11 rules, cout << cout should not compile at all, as the operator is declared explicit and thus cannot participate in implicit conversions. That was in fact the primary motivation for the change - preventing nonsensical code from compiling. A compiler that conforms to either standard would not produce a program that prints "1".
Apparently, certain C++ implementations allow mixing and matching the compiler and the library in such a way that produces non-conforming outcome (quoting #StephanLechner: "I found a setting in xcode which produces 1, and another setting that yields an address: Language dialect c++98 combined with "Standard library libc++ (LLVM standard library with c++11 support)" yields 1, whereas c++98 combined with libstdc (gnu c++ standard library) yields an address;"). You can have a C++03-style compiler that doesn't understand explicit conversion operators (which are new in C++11) combined with a C++11-style library that defines the conversion as operator bool(). With such a mix, it becomes possible for cout << cout to be interpreted as cout << cout.operator bool(), which in turn is simply cout << true and prints "1".
As Igor says, you get this with a C++11 library, where std::basic_ios has the operator bool instead of the operator void*, but somehow isn't declared (or treated as) explicit. See here for the correct declaration.
For example, a conforming C++11 compiler will give the same result with
#include <iostream>
using namespace std;
int main() {
cout << "2+3 = " <<
static_cast<bool>(cout) << 2 + 3 << endl;
}
but in your case, the static_cast<bool> is being (wrongly) allowed as an implicit conversion.
Edit:
Since this isn't usual or expected behaviour, it might be useful to know your platform, compiler version, etc.
Edit 2: For reference, the code would usually be written either as
cout << "2+3 = "
<< 2 + 3 << endl;
or as
cout << "2+3 = ";
cout << 2 + 3 << endl;
and it's mixing the two styles together that exposed the bug.
The reason for the unexpected output is a typo. You probably meant
cout << "2+3 = "
<< 2 + 3 << endl;
If we ignore the strings that have the expected output, we are left with:
cout << cout;
Since C++11, this is ill-formed. std::cout is not implicitly convertible to anything that std::basic_ostream<char>::operator<< (or a non member overload) would accept. Therefore a standards conforming compiler must at least warn you for doing this. My compiler refused to compile your program.
std::cout would be convertible to bool, and the bool overload of the stream input operator would have the observed output of 1. However, that overload is explicit, so it shouldn't allow an implicit conversion. It appears that your compiler/standard library implementation doesn't strictly conform to the standard.
In a pre-C++11 standard, this is well formed. Back then std::cout had an implicit conversion operator to void* which has a stream input operator overload. The output for that would however be different. it would print the memory address of the std::cout object.
The posted code should not compile for any C++11 (or later conformant compiler), but it should compile without even a warning on pre C++11 implementations.
The difference is that C++11 made the convertion of a stream to a bool explicit:
C.2.15 Clause 27: Input/output library [diff.cpp03.input.output]
27.7.2.1.3, 27.7.3.4, 27.5.5.4
Change: Specify use of explicit in existing boolean conversion operators
Rationale: Clarify intentions, avoid workarounds.
Effect on original feature: Valid C++ 2003 code that relies on implicit boolean conversions will fail to
compile with this International Standard. Such conversions occur in the following conditions:
passing a value to a function that takes an argument of type bool;...
ostream operator << is defined with a bool parameter. As a conversion to bool existed (and was not explicit) is pre-C++11, cout << cout was translated to cout << true which yields 1.
And according to C.2.15, this should not longer compile starting with C++11.
You can easily debug your code this way. When you use cout your output is buffered so you can analyse it like this:
Imagine first occurence of cout represents the buffer and operator << represents appending to the end of the buffer. Result of operator << is output stream, in your case cout. You start from:
cout << "2+3 = " << cout << 2 + 3 << endl;
After applying the above stated rules you get a set of actions like this:
buffer.append("2+3 = ").append(cout).append(2 + 3).append(endl);
As I said before the result of buffer.append() is buffer. At the begining your buffer is empty and you have the following statement to process:
statement: buffer.append("2+3 = ").append(cout).append(2 + 3).append(endl);
buffer: empty
First you have buffer.append("2+3 = ") which puts the given string directly into the buffer and becomes buffer. Now your state looks like this:
statement: buffer.append(cout).append(2 + 3).append(endl);
buffer: 2+3 =
After that you continue to analyze your statement and you come across cout as argument to append to the end of buffer. The cout is treated as 1 so you will append 1 to the end of your buffer. Now you are in this state:
statement: buffer.append(2 + 3).append(endl);
buffer: 2+3 = 1
Next thing you have in buffer is 2 + 3 and since addition has higher precedence than output operator you will first add these two numbers and then you will put the result in buffer. After that you get:
statement: buffer.append(endl);
buffer: 2+3 = 15
Finally you add value of endl to the end of the buffer and you have:
statement:
buffer: 2+3 = 15\n
After this process the characters from the buffer are printed from the buffer to standard output one by one. So the result of your code is 2+3 = 15. If you look at this you get additional 1 from cout you tried to print. By removing << cout from your statement you will get the desired output.
Could I say that in C++, each statement(without the semicolon) is also an expression?
Also, all expressions, add a semicolon, can become a statement?
Thanks.
No, a C++ statement is not always an expression. For example a for loop is not an expression (of type void). So even with using the comma operator the following is wrong:
/// wrong code, syntactically incorrect in C++
for (int i=0; i<5; i++) {std::cout<<i<<std::endl;}
, // this is a comma operator
x+3
(and you could replace the comma operator by any other operator like +, it is still wrong)
But of course expressions (including assignments and calls) can be used as statements.
Notice that GCC provides, as a language extension, statement exprs (and this extension is accepted by Clang/LLVM); here is a trivial example (the value of the statement expression is given by 2*x):
#include <iostream>
void f (int x) {
// notice the statement-expr starting inside ({ ... })
// the last expression inside the braces gives the value
int y = ({std::cout << "x=" << x << std::endl; 2*x;})+1;
std::cout << "y=" << y << std::endl;
}
With C++11 compilers not accepting that extension, you might create a closure with a lambda-expression and apply it immediately to get an equivalent effect:
void f (int x) {
int y = ([=](){std::cout << "x=" << x << std::endl; return 2*x;})() + 1;
std::cout << "y=" << y << std::endl;
}
Hopefully an optimizing compiler won't bother creating the intermediate closure and produce code equivalent to what GCC could give (with g++ -O2) with the statement expr variant
Some languages, notably Ocaml, Scheme, Haskell, don't have statements or instructions. They have only expressions (and some of them might have some side-effect).
An expression followed by a semicolon is indeed an expression_statement which is a type of statement.
But the converse is not necessarily true: for example consider the jump_statement:
goto foo;
here goto foo is not an expression.
No.
Statements can be composed of any number of things (including expressions), but statements themselves are not expressions.
Have a look at §A.5.
look at the following simple code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s("1234567890");
string::iterator i1 = s.begin();
string::iterator i2 = s.begin();
string s1, s2;
s1.append(i1, ++i1);
s2.append(++i2, s.end());
cout << s1 << endl;
cout << s2 << endl;
}
what would you expect the output to be?
would you, like me, expect it to be:
1
234567890
wrong!
it is:
234567890
i.e. the first string is empty.
seams that prefix increment operator is problematic with iterators. or am I missing something?
You're missing something: this really has nothing to do with iterators. The order in which arguments to a function are evaluated is unspecified. As such your: append(i1, ++i1); would depend on unspecified behavior, regardless of the type of i1. Just for example, given something a lot simpler like:
void print(int a, int b) {
std::cout << a << " " << b << "\n";
}
int main() {
int a =0;
print(a, ++a);
return 0;
}
Your output could perfectly reasonably be the "0 1" you seem to expect, but it could also perfectly reasonably be: "1 1". Since this is unspecified, it could change from one version of the compiler to the next, or even with the same compiler when you change flags, or (in theory) could vary depending on the phase of the moon...
C++ implementations are free to evaluate arguments in any order. In this case, if ++i1 is evaluated first, you will get an empty string.
Not a bug.
The order in which the arguments to
s1.append(i1, ++i1);
are evaluated is not specified by the standard. The compiler is free to use any order it chooses. In this case, it evaluates the second argument (++i1) before the first (i1) and you specify a null range to copy.
The C++ standard does not specify anything about the order in which the function arguments are evaluated, making it implementation dependent. C++ requires that the arguments to a function be completely evaluated (and all side-effects posted) prior to entering the function, but the implementation is free to evaluate the arguments in any order
In your case i++ got evaluated before making both the parameters same, resulting in an empty string.
More info on this behavior here on comp.compilers newsgroup