Why do different C++ compilers give different results for this code? - c++

I'm writing some C++ codes for fun and practice, to learn more about language features. I want to know more about static variables and their behaviour in recursive functions. Trying this code in g++ compiler, I'm given expected result:
#include <iostream>
using namespace std;
int f(const int& value)
{
static int result = 0;
return result += value;
}
int main()
{
cout << f(10) << ", " << f(f(10)) << ", " << f(f(f(10)));
return 0;
}
But my friend tested same code in Microsoft Visual C++ 6. output is 50, 80, 90 I tested it with other C++ compilers (g++, Borland, Code::blocks and MingW under Linux, Win and Mac) output was 110, 100, 40. I can't understand how output could be 50, 80, 90 ...
Why MSVC's output is different?

The order of evaluation of the following three subexpressions is unspecified:
f(10)
f(f(10))
f(f(f(10)))
The compiler may evaluate those subexpressions in any order. You should not rely on a particular order of evaluation in your program, especially if you intend to compile using multiple compilers.
This is because there is no sequence point anywhere in that expression. The only requirement is that each of those subexpressions is evaluated before the result is needed (that is, before the result is to be printed).
In your example, there are actually several subexpressions, which I've labelled as a through k here:
// a b c d e f g h i j k
cout << f(10) << ", " << f(f(10)) << ", " << f(f(f(10)));
The calls to operator<< (a, c, d, g, and h) all have to be evaluated in order because each depends on the result of the previous call. Likewise, b has to be evaluated before a can be evaluated, and k has to be evaluated before j, i, or h can be evaluated.
However, there are no dependencies between some of these subexpressions: the result of b is not dependent upon the result of k, so the compiler is free to generate code that evaluates k then b or b then k.
For more information on sequence points and related unspecified and undefined behavior, consider reading the Stack Overflow C++ FAQ article, "Undefined Behavior and Sequence Points" (your program doesn't have any undefined behavior, but much of the article still applies).

Just because the output appears left-to-right on the screen does not mean the order of evaluation follows the same direction. In C++, the order of evaluation of function arguments is unspecified. Plus, printing data via the << operator is just fancy syntax for calling functions.
In short, if you say operator<<(foo(), bar()), the compiler can call foo or bar first. That's why it's generally a bad idea to call functions with side effects and use those as arguments to other functions.

An easy way to see exactly what it is doing:
int f(const int& value, int fID)
{
static int result = 0;
static int fCounter = 0;
fCounter++;
cout << fCounter << ". ID:" << fID << endl;
return result += value;
}
int main()
{
cout << f(10, 6) << ", " << f(f(10, 4), 5) << ", " << f(f(f(10, 1),2),3);
return 0;
}
I agree with what others have said in their answers, but this would allow you to see exactly what it is doing. :)

The prefix operator syntax is translated into the following prefix notation:
<<( <<( <<( cout, f(10) ), f(f(10)) ), f(f(f(10))) )
A B C
Now there are three different function calls, identified as A, B and C above. with the arguments of each call being:
arg1 arg2
A: result of B, f(10)
B: result of C, f(f(10))
C: cout , f(f(f(10)))
For each one of the calls, the compiler is allowed to evaluate the arguments in any order, for the correct evaluation of the first argument of A, B has to be evaluated first, and similarly for the first argument of B, the whole C expression has to be evaluated. This implies that there is a partial order on the execution of A, B, and C required by the first argument dependency. There is also a partial ordering on the evaluation of each call and both arguments, so B1 and B2 (referring to the first and second arguments of the call B) have to be evaluated before B.
Those partial orderings do not lead to a unique requirement for the execution of the calls, since the compiler can decide to execute all second arguments before trying to evaluate the first argument, leading to the equivalent path:
tmp1 = f(10); tmp2 = f(f(10)); tmp3 = f(f(f(10)));
cout << tmp1 << tmp2 << tmp3;
or
tmp3 = f(f(f(10))); tmp2 = f(f(10)); tmp1 = f(10);
cout << tmp1 << tmp2 << tmp3;
or
tmp2 = f(f(10)); tmp1 = f(10); tmp3 = f(f(f(10)));
cout << tmp1 << tmp2 << tmp3;
or ... keep combining.

Related

How do we properly use pointers and references to integers in a function (C++)?

I am having trouble understanding how to obtain the correct values outputted by the following C++ code when trying to solve it by hand.
#include <iostream>
using namespace std;
int f(int a, int & b,int *c){
a += 1;
b += 3;
*c += 4;
return a+b+(*c);
}
int main() {
int a = 3, b = 4,c = 5;
cout << "total: " << f(b,c,&a) << endl;
cout << "a= " << a << " b= " << b << " c= " << c << endl;
a = 3, b = 4,c = 5;
cout << "total: " << f(a,a,&a) << endl;
cout << "a= " << a << " b= " << b << " c= " << c << endl;
return 0;
}
I know the result should be:
total: 20
a= 7 b= 4 c= 8
total: 24
a= 10 b= 4 c= 5
But everytime I try to solve this code by hand (attempt to write out the steps and assignments on a piece of paper) I can't seem obtain the correct total or values. Can anyone help me understand what is happening inside the function with a, b, and c (maybe a step-by-step explanation?). There must be something I am not understanding with the referencing/dereferencing or the pointers that is causing mistakes in my logic. Even ChatGPT is spitting out the incorrect answer after trying to execute the code...
For example if I try the first set of of inputs inside the function, here's what I understand:
int a = 4;
int &b = 5; //since c = 5
int *c = &a; //&a = 3
Then I start to execute the body of the function:
a += 1 now gives me a = 5;
b += 3 now gives me c = 8 since b is a reference to c so it really only is c that changes;
*c += 4 now takes the value stored in &a initialized as 3 and adds 4 so a's new value is 7;
The final tally is a = 7, b = 4 (hasn't changed), and c = 8. These values are correct, but the return portion of the function does not work with these values:
a+b+(*c) should be 7+4+(7), but the result of that is 18, while the correct answer is 20.
What's worst is that if I use the same logic for the second time the function is called, my values are incorrect but my total is correct... I'm lost.
The final tally is a = 7, b = 4 (hasn't changed), and c = 8.
These values are correct, but the return portion of the function does not
work with these values:
What is getting you tripped up is that a, b, and c in your main are not the same as a, b, and c in the f(). The
return a+b+(*c);
Uses what f() knows as a, b, and c. This is part of f(). f()'s variables is the only thing that this return statement knows anything about, and it has absolutely no knowledge at all, whatsoever, about any variables in main. So to know what these variables are you just have to reread what you wrote yourself:
a += 1 now gives me a = 5;
b += 3 now gives me c = 8 since b is a reference
but this b, right here is the very exact, same b that's in the return expression.
*c += 4 now takes the value stored in &a initialized as 3 and adds 4 so a's new value is 7;
But this is the c in the expression. So
return a+b+(*c);
computes 5+8+7 or 20, as you've observed.
The second expression works the same way.
You're getting tripped up by the fact that f()'s variables use the same names as the variables in main(). It also doesn't help that pointers and references from one refer to variables in the other.
It might be helpful for you to rename the variables in f():
int f(int x, int & y,int *z){
x += 1;
y += 3;
*z += 4;
return x+y+(*z);
}
This should be logically equivalent to the original function, but with less confusion.
This is easiest to do with pictures, so I'll try to make some ascii art that shows what is going on.
Here is the situation just after the first call has entered f:
main a:3 b:4 c:5
^ ^
| /---/
| /
f c:* b:* a:4
Here 'main' and 'f' each have their own 'a', 'b', and 'c'; and 'b' and 'c' in 'f' point at/refer to things in main's stack frame. I've reversed the order c/b/a in 'f' in order to not have crossing lines.
After the 3 adds in f, we have
main a:7 b:4 c:8
^ ^
| /---/
| /
f c:* b:* a:5
In the second call to f, things look like:
main a:3 b:4 c:5
^
|\--\
| \
f c:* b:* a:3
and after the adds:
main a:10 b:4 c:5
^
|\--\
| \
f c:* b:* a:4

evaluation of passed parameters in macros

#define prod(a) (a*a)
using namespace std;
int main()
{
int i = 3, j, k, l;
j = prod(i++);
cout << i << endl;
k = prod(++i);
cout << i << endl;
l = prod(i+1);
cout << i << " " << j << " " << k << " " << l;
}
Why is variable "i" incremented twice?
i.e to 5 from 3 after j=prod(i++);
Remember that macros are expanded in the source code, not actually called or evaluated.
That means a "call" like
prod(i++)
results in the expanded code
i++*i++
being seen by the compiler.
Many compilers allow you to stop after preprocessing, or otherwise generate preprocessed source, that you can examine to see macro expansions.
If you continue using such a macro with other expressions as arguments, you will soon see another reason they are bad.
Lets say you use
prod(2+4)
Then that will result in the expansion
2+4*2+4
which is equal to
2+(4*2)+4
which is equal to 14, not 36 which might have been expected.
Why is variable "i" incremented twice? i.e to 5 from 3 after j=prod(i++)
Because prod() is a macro, not a function, so
k=prod(++i);
become
k=(++i * ++i);

Why does this C++ code output the result?

This is the C++ code:
#include<iostream>
using namespace std;
int a=8;
int fun(int &a)
{
a=a*a;
return a;
}
int main()
{
cout << a << endl \
<< fun(a) << endl \
<< a << endl;
return 0;
}
why does it output:
64 64 8
the << operator's associativity is left to right, so why not output 8 64 64?
Does it have the relation to the sequence point and the effect side?
Associativity and evaluation order are not the same thing. The expression a << b << c is equivalent to (a << b) << c due to left-to-right associativity, but when it comes to evaluation order, the compiler is free to evaluate c first then a << b and, likewise, it can evaluate b before it evaluates a. In fact, it can even evaluate the terms in the order b → c → a if it wants, and it just might if it concludes that such an order will maximise performance by minimising pipeline stalls, cache misses, etc.

return (a) vs. return a

I have seen both in the C and C++ code I have been looking at.
What is the difference?
No difference at all.
The official syntax is return something; or return; and of course it is a keyword, not a function.
For this reason you should not read it as return( a ); but as return (a);
I think the difference is subtle but clear, parentheses will not apply to return but to a.
((((a)))) is the same as (a) that is the same as a.
You can also write something like...
int x = (((100)));
You can also write something like...
printf("%d\n", (z));
As someone said in the comments, there is now, with C++11 (2011 version of the C++ language) the new operator decltype. This operator introduces a new example where (a) is different from a, this is quite esoteric and a little out of topic but I add this example just for the purpose of completeness.
int x = 10;
decltype(x) y = x; // this means int y = x;
decltype((x)) z = x; // this means int& z = x;
y = 20;
z = 30;
std::cout << x << " " << y << " " << z << std::endl;
// this will print out "30 20 30"
Students will not be interested in this, as I said, too esoteric, and it will work only with compilers that supports at least part of the C++11 standard (like GCC 4.5+ and Visual Studio 2010).
This goes in contrast also with the use of typeid keyword:
int a;
std::cout << typeid(a).name() << std::endl; // will print "int"
std::cout << typeid((a)).name() << std::endl; // will print "int" !!!!
Writing return x indicates a programmer who understands what return means. Whereas return(x) indicates a programmer who incorrectly believes that return is a kind of function.
return is not a function.
It is more a point of style. I personally do not use parentheses in a return statement unless it is showing order of operations.
examples
return a;
return (a || b);
return (a && (b || c));
return (a ? b : c);

operator << : std::cout << i << (i << 1);

I use the stream operator << and the bit shifting operator << in one line.
I am a bit confused, why does code A) not produce the same output than code B)?
A)
int i = 4;
std::cout << i << " " << (i << 1) << std::endl; //4 8
B)
myint m = 4;
std::cout << m << " " << (m << 1) << std::endl; //8 8
class myint:
class myint {
int i;
public:
myint(int ii) {
i = ii;
}
inline myint operator <<(int n){
i = i << n;
return *this;
}
inline operator int(){
return i;
}
};
thanks in advance
Oops
Your second example is undefined behavior.
You have defined the << operator on your myint class as if it were actually <<=. When you execute i << 1, the value in i is not modified, but when you execute m << 1, the value in m is modified.
In C++, it is undefined behavior to both read and write (or write more than once) to a variable without an intervening sequence point, which function calls and operators are not, with respect to their arguments. It is nondeterministic whether the code
std::cout << m << " " << (m << 1) << std::endl;
will output the first m before or after m is updated by m << 1. In fact, your code may do something totally bizarre, or crash. Undefined behavior can lead to literally anything, so avoid it.
One of the proper ways to define the << operator for myint is:
myint operator<< (int n) const
{
return myint(this->i << n);
}
(the this-> is not strictly necessary, just my style when I overload operators)
Because int << X returns a new int. myint << X modifies the current myint. Your myint << operator should be fixed to do the former.
The reason you're getting 8 for the first is that apparently m << 1 is called first in your implementation. The implementation is free to do them in any order.
Your << operator is in fact a <<= operator. If you replace the line with
std::cout << i << " " << (i <<= 1) << std::endl; //8 8
you should get 8 8.
since m is a myInt your second example could be rewritten as:
std::cout << m << " " << (m.operator<<( 1)) << std::endl;
The order of evaluation for the subexpressions m and (m.operator<<( 1)) is unspecified, so there's no saying which "m" you'll get for the 1'st expression that m is used in (which is a simple m expression). So you might get a result of "4 8" or you might get "8 8".
Note that the statement doesn't result in undefined behavior because there are sequence points (at least one function call) between when m is modified and when it's 'read'. But the order of evaluation of the subexpressions is unspecified, so while the compiler has to produce a result (it can't crash - at least not legitimately), there's no saying which of the two possible results it should produce.
So the statement is about as useful as one that has undefined behavior, which is to say it's not very useful.
Well (m << 1) is evaluated before m and therefore m holds 8 already, as in your operator<< you overwrite your own value.
This is wrong behaviour on your side, the operator<< should be const and not change your object.
Because the << operator of myint modifies its lhs. So after evaluating m << 1, m will actually have the value 8 (while i << 1 only returns 8, but does not make i equal to 8). Since it is not specified whether m<<1 executes before cout << m (because it's not specified in which order the arguments of a function or operator are evaluated), it is not specified whether the output will be 8 8 or 4 8.
The C++ language does not define the order of evaluation of operators. It only defines their associativity.
Since your results depend on when the operator<< function is evaluated within the expression, the results are undefined.
Algebraic operator $ functions should always be const and return a new object:
inline myint operator <<(int n) const { // ensure that "this" doesn't change
return i << n; // implicit conversion: call myint::myint(int)
}