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.
Related
Confused about the output for the second code snippet. Why is the output different than the first program?
#include <iostream>
using namespace std;
int main() {
int s[5] = {1, 2 , 3, 4, 5};
int *p = s;
int first = *(p++);
int second = *++p;
int third = ++*p;
int fourth = *p++;
cout << "*p++ is " << first << endl
<< "*++p is " << second << endl
<< "++*p is " << third << endl
<< "*p++ is " << fourth << endl;
return 0;
}
output:
*p++ is 1
*++p is 3
++*p is 4
*p++ is 4
https://ideone.com/Qu2uIJ
I expected the output would be the same in the code below:
#include <iostream>
using namespace std;
int main() {
int s[5] = {1, 2 , 3, 4, 5};
int *p = s;
cout << "*p++ is " << *p++ << endl
<< "*++p is " << *++p << endl
<< "++*p is " << ++*p << endl
<< "*p++ is " << *p++ << endl;
return 0;
}
output:
*p++ is 3
*++p is 3
++*p is 3
*p++ is 1
https://ideone.com/nwd7xR
What's going on?
Your statement cout << "*p++ is " << *p++ << endl << ...; is treated as one expression, and C++ is almost free in the order of evaluating the arguments used in expressions. SO it is undefined (behaviour actually) in which order the p++ and ++-statements are evaluated.
In the first approach, evaluation order is according to the variables to which you assign. In the second, C++ is free (and treats it as UB if there is no sequence point in the expression; in your's, there isn't a sequence point).
As per operator precedence, operator << is left to right which occurs in cout object in sequence one after the other and sequence of evaluation of arguments to operator << is unspecified.
Between consecutive "sequence points" an object's value can be
modified only once by an expression.
https://msdn.microsoft.com/en-us/library/azk8zbxd.aspx
The second code snippet attempts to modify the pointer's value multiple times within one sequence.
List of C Sequence Points:
Left operand of the logical-AND operator (&&).
Left operand of the logical-OR operator (||).
Left operand of the comma operator (,)
Function-call operator ()
First operand of the conditional operator aka ternary operator ( ? : )
The end of a full initialization expression (that is, an expression
that is not part of another expression such as the end of an
initialization in a declaration statement).
The expression in an expression statement. Expression statements
consist of an optional expression followed by a semicolon (;). The
expression is evaluated for its side effects and there is a sequence
point following this evaluation.
The controlling expression in a selection (if or switch) statement.
The controlling expression of a while or do statement.
Each of the three expressions of a for statement.
The expression in a return statement.
I am quite new to C++, I know that shift operator in C++ is overloaded. But as how we can do shift operation within printf statement in C can we do similar shift operation in cout statement.
Well, just try it...
#include <iostream>
int main() {
int k = 1;
std::cout << (k << 1) << std::endl; // Correct shifting - notice the parentheses
std::cout << k << 1 << std::endl; // Wrong
return 0;
}
Output:
2
11
What matters here is the type of the variables used for the << operator.
The parentheses causes it to be int << int which is the bitwise shifting. Without the parentheses it will be ostream << int which will write the int to the stream.
Decrementation / Incrementation is a basic operation but it's precendence on - -- and + ++ confused me. I'll use decrementation for illustration:
I have a set here of different styles of operating between a and b: See it working here
#include <iostream>
using namespace std;
int a=10, b=7;
int main() {
// - and -- opearator // Results: Details:
a = 10, b = 7; cout << a---b << endl; // 3 a post-decrement
a = 10, b = 7; cout << a ---b << endl; // 3 a post-decrement
a = 10, b = 7; cout << a- --b << endl; // 4 b pre-decrement
a = 10, b = 7; cout << a-- -b << endl; // 3 a post-decrement
a = 10, b = 7; cout << a--- b << endl; // 3 a post-decrement
return 0;
}
I understand that the 4 output came from the decremented b which is 7 that turned to 6 and is subtracted from a which is 10.
Also, because of the other four statements, I thought the compiler treats all of them as --- but behold, here comes the confusion of - -- results. See it working here
Parsing follows the maximal munch rule, so all statements minus the third are interpreted as (a--)-b which decrements a and returns its previous value (which was 10).
The third one is a-(--b) which is a pre-decrement on b, so the new decremented value is returned.
I think this is because of the Maximal Munch Rule. From Wiki:
In computer programming and computer science, "maximal munch" or
"longest match" is the principle that when creating some construct, as
much of the available input as possible should be consumed.
From Expert C Programming:
The ANSI standard specifies a convention that has come to be known as
the maximal munch strategy. Maximal munch says that if there's more
than one possibility for the next token, the compiler will prefer to
bite off the one involving the longest sequence of characters.
But why didn't it decremented after it's statement?
Because the --X operator:
first performs the decrement
then returns the result of decrementing
So, there's no way that --b will 'decrement afterwards'. It always does it "before".
Confusion
Look carefully at code and results: Everytime where --- is written without spaces, the result is the same: three. Three is also the result for -- - case. Even with a pure guess, you could say that compiler parses it as -- -. In fact, it actually does it like that, because the C++ Standard requires it to do so. See comments about 'maximum munch' rule. Same follows for other multi-character operators, like ++.
In the other case where you have split that into - --, the compiler had no other option: it had to treat it literally as - -- because of the space in the middle. Just as -- -, this case is obvious and it's perfectly visible which part forms the -- operator and the compiler must obey that.
That statement is equivalent to 10-6 = 4,
rest are equivalent to 9-7 = 3.
#include <iostream>
using namespace std;
int a=10, b=7;
int main() {
// - and -- opearator // Results: Details after a statement:
cout << (a--)-b << endl; a=10, b=7; // 3 Both a and b decremented
cout << (a --)-b << endl; a=10, b=7; // 3 Both a and b decremented
cout << a- (--b) << endl; a=10, b=7; // 4 Neither a or b decremented
cout << (a--) -b << endl; a=10, b=7; // 3 Both a and b decremented
cout << (a--)- b << endl; a=10, b=7; // 3 Both a and b decremented
return 0;
}
In this series of statements
cout << a---b << endl; a=10, b=7; // 3 Both a and b decremented
cout << a ---b << endl; a=10, b=7; // 3 Both a and b decremented
cout << a- --b << endl; a=10, b=7; // 4 Neither a or b decremented
cout << a-- -b << endl; a=10, b=7; // 3 Both a and b decremented
cout << a--- b << endl; a=10, b=7; // 3 Both a and b decremented
you forgot to include one more statement:)
cout << a --- b << endl; a=10, b=7; // 3 Both a and b decremented
In all these statements
cout << a---b << endl; a=10, b=7; // 3 Both a and b decremented
cout << a ---b << endl; a=10, b=7; // 3 Both a and b decremented
cout << a--- b << endl; a=10, b=7; // 3 Both a and b decremented
cout << a --- b << endl; a=10, b=7; // 3 Both a and b decremented
The compiler parses outputed expression as
a-- -b
that is it tries to extract the longest valid token.
The value of the postdecrement operator as for example a-- is the value of its operand before decrementing. So in expression
a-- -b
the value of a-- is 10 and the value of b is 7. The difference is equal to 3.
And you have the only expression with the predecrement operator
cout << a- --b << endl; a=10, b=7; // 4 Neither a or b decremented
There the value of --b is the value of b after decrementing that is 6. So you have 10 - 6 that is equal to 4.
If you will substitute minus to plus in all these statements you will get the same effect
17
17
18
17
17
17 // this corresponds to my added statement a +++ b
So these operations - -- and + ++ behave in essense the same way.
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.
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)
}