This question already has answers here:
order of evaluation of operands
(6 answers)
Closed 14 days ago.
I have a code. The code prints 1236 (g++ 7.5.0)
Does the output depend on the compiler? (e.g. output can be 3216)
#include <bits/stdc++.h>
using namespace std;
int foo(int& x) {
std::cout << ++x;
return x;
}
int main() {
int i = 0;
cout << foo(i) + foo(i) + foo(i) << endl; // 1236
}
No, the output does not depend on the compiler (modulo the bits/stdc++.h nonsense). The order in which the three calls foo(i) are evaluated is unspecified, but that doesn't affect the output: function calls are not interleaved, so some call will increment i to 1, print that, and return it (as a copy), then one of the other two will assign, print, and return 2, then the last will do 3, and their return values will always sum to 6.
Note that if foo returned int&, the last output might be any digit 6–9, since the implementation might not choose to read i for the addition immediately upon return. The behavior would still be defined, though, since those reads would be indeterminately sequenced with respect to any write.
Related
This question already has an answer here:
Use pass by reference in recursion
(1 answer)
Closed 1 year ago.
I came across the following question:
#include <stdio.h>
int f(int &x, int c)
{
c = c - 1;
if (c == 0) return 1;
x = x + 1;
return f(x, c) * x;
}
int main()
{
int p = 5;
printf("%d", f(p, p));
}
As far as I have worked out, the recursion calls should work, and with each recursion call, value of c should reduce by 1 and value of x should increase by 1 . However, if I calculate it that way, the answer comes out to be 3024. However, on executing, the output comes out to be 6561. I am not really sure how this answer is coming.
I have the link to the article from where this question is taken, but I fail to understand how x will remain constant as is described in this link: https://www.geeksforgeeks.org/c-references-question-1/
Can someone help me with the working behind this code?
There can be any result, due to Undefined behavior.
Since the x is passed by reference, the last assign will matter. Thus, we have:
9*9*9*9*1=6561
We delay the evaluation of the f(x, c) * x, where all the subsequent recursive calls will have access to the x. We increment the x this way until the c is equal to 0, means we increment the x up to it being 9.
When we hit the base case (the c == 0), the current call returns 1, while the x is already 9.
Then we evaluate the multiplication 1 * x * x * x * x, where x is equal to 9. Thus, the 6561.
Flawless explanation? Not so much.
The fun part is that there is no concept of left-to-right or right-to-left evaluation in C++:
Order of evaluation of any part of any expression, including order of
evaluation of function arguments is unspecified (with some exceptions
listed below). The compiler can evaluate operands and other
subexpressions in any order, and may choose another order when the
same expression is evaluated again.
Means, that though this logic gets a pass this time, it may won't be this way next time for me or if you run it yourself.
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 21 days ago.
#include<iostream>
#include<conio.h>
using namespace std;
int main()
{
int y,**p,*pt;
int x=5;
pt=&x;
p=&pt;
y=**p + ++(**p);
cout<<*pt<<" "<<**p<<" "<<x<<" "<<y;
getch();
return(0);
}
output generated 6 6 6 11, why not 6 6 6 12 kindly guide on execution step.
Here my doubt is **p is pointing to x only which is incremented by second operand ++(**p). so value of y should be 12.
This is classic undefined behaviour! There is no guarantee in the C++ standard about the order of evaluation of the operands of the + operator in y=**p + ++(**p).
I tested your code in MSVC and clang-cl and I get the output: 6 6 6 12 - which suggests (as you expect) that ++(**p) is evaluated first. However, on your compiler, it seems that the LHS is evaluated first.
From the cppreference site linked in the comments by Scheff:
Order of evaluation of any part of any expression, including order of
evaluation of function arguments is unspecified (with some exceptions
listed below). The compiler can evaluate operands and other
subexpressions in any order, and may choose another order when the
same expression is evaluated again. There is no concept of
left-to-right or right-to-left evaluation in C++….
PS: Interestingly, changing to y = ++(**p) + **p; also gives 6 6 6 12 as the output.
Consider the following c++ code for a simple binary tree DFS traversal:
#include <iostream>
#include <vector>
using namespace std;
int print_vector(vector<char> *vec){
for (auto &it: *vec)
cout<<it;
cout<<'\n';
return 0;
}
int btree_dfs_traversal(int max_depth, int cur_depth, vector<char> position){
if (cur_depth>max_depth)
return 0;
print_vector(&position);
vector<char>left = position;
vector<char>right = position;
left.push_back('l');
right.push_back('r');
return btree_dfs_traversal(max_depth, cur_depth+1, left)+btree_dfs_traversal(max_depth, cur_depth+1, right);
}
int main(int argc, const char * argv[]) {
vector<char> pos;
btree_dfs_traversal(4, 0, pos);
return 0;
}
The function(a minimal example) visits a binary tree, and prints the "position" of each node it visits. The only difference with a standard DFS is that (this part made the difference), most implementation uses a iteration for visiting the two nodes, while my the return statement returns the sum of two visits.
I expected the program to recurse from the left statement, i.e. the output starts with l, ll, lll, ... And indeed in my system(OSX) it is like this, and ideone has this output too.
However, in some friends' system, the output is different. The recursion starts from the right statement, i.e. r, rr... Unfortunately, I do not have exact information of their complier information at present.
My question is: is the sum of two recursion being a undefined behavior such that different compiler can produce different results? Or, it is just wrong to start from right?
The "problem" is that in f(1) + f(2) it is unspecified which function call comes first. Different compilers will pick different order and the order can depend on any number of unrelated factors. From the C++ reference:
Order of evaluation
Order of evaluation of the operands of almost all C++ operators (including the order of evaluation of function arguments in a function-call expression and the order of evaluation of the subexpressions within any expression) is unspecified. The compiler can evaluate operands in any order, and may choose another order when the same expression is evaluated again.
There are exceptions to this rule which are noted below.
Except where noted below, there is no concept of left-to-right or right-to-left evaluation in C++. This is not to be confused with left-to-right and right-to-left associativity of operators: the expression f1() + f2() + f3() is parsed as (f1() + f2()) + f3() due to left-to-right associativity of operator+, but the function call to f3 may be evaluated first, last, or between f1() or f2() at run time.
See http://en.cppreference.com/w/cpp/language/eval_order for exceptions and more info.
Consider the code:
#include<iostream>
using namespace std;
int refcube(double &ra)
{
ra*=ra*ra;
return ra;
}
int main()
{
auto x=2.0;
cout<<"cube of "<<x<<" is "<<refcube(x)<<endl;
return 0;
}
The output is:
cube of 8 is 8
Why the value of x at the first is displaying as 8 instead of 2?
Because evaluation order is not specified.
The compiler may generate the code to call refcube(x) and compute its value before or after generating the code to obtain the value of x, for output to std::cout.
Your compiler chose to compile this C++ code as calling refcube(x) first, and then by evaluating x.
The C++ language specification spends quite a few pages on the topic of "sequencing", which (very loosely speaking) specifies the evaluation order. To make a long story short, in this example, x is not sequenced with respect to refcube(x), in the expression that generates the output to std::cout, and such a compiler is free to compile either portion of the expression first.
According to the n4296 C++ standard document:
[dcl.init.list] (8.5.4.4) (pg223-224)
Within the initializer-list of a braced-init-list, the
initializer-clauses, including any that result from pack expansions
(14.5.3), are evaluated in the order in which they appear. That is,
every value computation and side effect associated with a given
initializer-clause is sequenced before every value computation and
side effect associated with any initializer-clause that follows it in
the comma-separated list of the initializer-list. [Note: This
evaluation ordering holds regardless of the semantics of the
initialization; for example, it applies when the elements of the
initializer-list are interpreted as arguments of a constructor call,
even though ordinarily there are no sequencing constraints on the
arguments of a call. —end note ]
(emphasis mine)
The note was added here: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1030
This reads to me that the following code:
#include <iostream>
struct MyType {
MyType(int i, int j, int k, int l)
: sum(i + j + k + l)
{
}
int sum;
};
int main()
{
int i = 0;
std::cout << MyType{ ++i, ++i, ++i, ++i }.sum << '\n';
}
Should print "10".
This is my reasoning:
MyType is being initialized via a braced-init-list
braced-init-lists are evaluated in order
even when it is interpreted as arguments of a constructor call
this means that it should be evaluated as MyType(1,2,3,4)
That is to say, the above code should behave exactly like this code:
#include <initializer_list>
#include <iostream>
int main()
{
int i = 0;
std::initializer_list<int> il{++i, ++i, ++i, ++i};
std::cout << *il.begin() + *(il.begin() + 1) + *(il.begin() + 2) + *(il.begin() + 3) << '\n';
}
But it does not. The first example prints '16' and the second example prints '10'
Literally every compiler from every vendor that I can get my hands on prints '16', seemingly ignoring that part of the standard and not inserting sequence points.
What am I missing here?
Note: The following seem to be related to this question:
(Optimization?) Bug regarding GCC std::thread
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51253
The answer seems to be that yes, this is a bug in both GCC and MSVC.
This is the status of this issue:
There are several bugs against GCC regarding init-list rules. Most of them have gone completely unacknowledged by the GCC team. This at least implies that G++ does have bugs here because the issues have not been closed as invalid
I have received unofficial word from the MSVC compiler team that this is in fact a bug in their compiler and they are working internally to fix it. However, I have no external bug to point to. As of MSVC 2015 Update 3, the old behavior remains.
Clang, which at this point is by far the most pedantic standards-complaint compiler, implements it the way the standard seems to read.
My personal investigation, discussions with C++ experts at conferences, and unofficial answers I've received from compiler developers indicates that this is a bug in MSVC and GCC, but I'm always reluctant to answer my own questions on StackOverflow. But here we are.
This note is not related to evaluation order. As it was stated in one of comments, it's about order of converting actual parameters to rvalues and standard does not define such order.
You should receive following warning (gcc):
17:58: warning: operation on 'i' may be undefined [-Wsequence-point]
I modified a program slightly to demonstrate how evaluation of arguments work with {} and ().
With such modification, program does not depend on order of converting lvalue to rvalue, thus does not have ambiguity which disappointed you.
#include <iostream>
struct MyType {
MyType(int i, int j)
: sum(i + j)
{
}
int sum;
};
int main()
{
int i = 0;
int a,b;
std::cout << MyType{ (a = ++i), (b = ++i) }.sum << '\n';
std::cout << "Here clauses are evaluated in order they appear: a=" << a << ", b=" << b << std::endl;
i = 0;
std::cout << MyType( (a = ++i), (b = ++i) ).sum << '\n';
std::cout << "Here order of evaluation depends on implementation: a=" << a << ", b=" << b << std::endl;
}
And the output of this program for clang and gcc:
clang:
3
Here clauses are evaluated in order they appear: a=1, b=2
3
Here order of evaluation depends on implementation: a=1, b=2
gcc:
3
Here clauses are evaluated in order they appear: a=1, b=2
3
Here order of evaluation depends on implementation: a=2, b=1
As you can see, in case of curly brackets, clauses are evaluated in order of appearance under both compilers, which corresponds to the note you provided.