periorities and associativity ?

may someone explain to me why this code :
1
2
3
4
5
6
7
#include <iostream>
using namespace std;
int main() {
int i = 0;
cout << i++ << ++i << i++;
return 0;
}

outputs 230 ?
Last edited on
It could also have hidden all your left socks and stolen your girlfriend.

http://www.cplusplus.com/faq/beginners/undefined/
@Duoas : LOL :D okay but this is not exactly the question i wanted to ask, regarding this code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   #include <iostream>
    using namespace std;
    class Int {
    public:
        int v;
        Int(int a) { v = a; }
        Int &operator++(int x) {
            v+=2;
            return *this;
        }
        
    };
    
    ostream &operator <<(ostream &o, Int &a) {
        return o << a.v;
    }
    
    int main() {
        Int i = 0;
        cout << i++ << i.v;
        return 0;
    }

why it outputs 20 ? why did it evaluate i.v before i++ ??
why did it evaluate i.v before i++ ??
Duoas wrote:
It could also have hidden all your left socks and stolen your girlfriend.

http://www.cplusplus.com/faq/beginners/undefined/
Read again part called unspecified behavior. It describes exactly the problem you have. Order of operator operands evaluation is unspecified. i.v might be calculated first. i++ might be calculated first. It might change with recompile and even with new launch of compiled programm.

GCC at least has the habit of evaluationg operands right-to-left, a it is generally easier to push results on stack and feed them to operators/functions called with left-to-right associativity that way.
It is exactly what you asked, and exactly the reason it isn't doing what you want: there is no prescribed sequencing for the operands to <<.

If you want it in a specific order, you must explicitly give a specific order:

1
2
cout << i++;
cout << i.v;
1
2
3
Int i0 = i++;
int i1 = i.v;
cout << i0 << i1;

Hope this helps.
i made 2 codes to ask about something, the 1st one :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
using namespace std;
class A {
public:
	int i;
	A(int i): i(i) {}
};
A operator* (A& a, A& b) {
	cout << "multiplication done\n";
	return A(a.i*b.i);
}
A operator/ (A& a, A& b) {
	cout << "division done\n";
	return A(a.i/b.i);
}
ostream& operator<< (ostream& os, A& a) {
	return os << a.i;
}
int main() {
	A a(4), b(3), c(2);
	cout << a*b / c << endl;
        return 0;
}

which outputs:

multiplication done
division done
6

2nd code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
using namespace std;
class A {
public:
	int i;
	A(int i): i(i) {}
};
A operator* (A& a, A& b) {
	cout << "multiplication done\n";
	return A(a.i*b.i);
}
A operator/ (A& a, A& b) {
	cout << "division done\n";
	return A(a.i/b.i);
}
A operator+ (A& a, A& b) {
	return A(a.i + b.i);
}
ostream& operator<< (ostream& os, A& a) {
	return os << a.i;
}
int main() {
	A a(3), b(4), c(2);
	cout << a*b+b / c << endl;
        return 0;
}

which outputs:

division done
multiplication done
14

the 1st code shows the associativity works (as '*' and '/' have the same periority) in which multiplication (the left side) is done first.
in the 2nd code the associativity won't work as they are separated by '+', we see the division (the right side) is done first.
does this mean that when 2 operators have the same periority and can't be evaluated in terms of associativity the right side will be evaluated first ?
Last edited on
It means neither. The associativity of the operators does not affect evaluation order.

Let's think for a moment about the following expression:

    a() + b() * c()

Mathematically, multiplication comes first, so b() * c() must be computed first.

However, there is no reason that b() and c() must be computed before a(). In fact, a(), b(), and c() can be invoked in any order. The FAQ I linked to you says this quite specifically. (I really do wish people would bother to read links posted for them.) It has even got a big pretty picture to help understand:
http://www.cplusplus.com/faq/beginners/undefined/#sequencing

The only important thing is that the multiplication happens before the addition.

As I specifically said above, if you want a specific order, you have to force it:

1
2
3
auto a_b = a * b;             // multiplication happens first
auto b_c = b / c;             // division happens second
cout << (a_b + b_c) << endl;  // addition happens last 

Hope this helps.
wikipedia.org/wiki/Operator_associativity
isn't grouping operators with same percedance from left to right for ex is indirect controlling of evaluation order?
but your example doesn't contain associativity for () as they are separated by + and /.
regarding 3*4/2 for ex: * and / have same percedance, but they are grouped from left to right, 3*4 first then 12/2.
Otherwise, 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.
http://en.cppreference.com/w/cpp/language/eval_order
that is what i said. there is no associativity in () here. regarding order of evaluation i didn't mention the () but mentioned * and / and said 3*4/2 would be like (3*4)/2. i mentioned only evaluating 3*4 first.
the summary is that operators with same percedance but not connected are evaluated at any order (like: cout << i++ << i++;) . while operators with same percedance and connected are evaluated in their associative order (like 3*4/2).
right ?
No. And this is the last time I'm going to bother answering the question.

You keep trying to assert that associative order somehow affects evaluation order of the operands. It does not..
if you felt bothered you could not bother yourself and answer from beginning. the evaluation word which bothers you i didn't use it in associativity except to state that 3*4/2 will be parsed as (3*4)/2. the explanations i made at last post demonstrated what i wanted to say and didn't try to change the evaluation order you are talking about.
Lets continue the fun.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
using namespace std;

class A {
public:
	int i;
	A(int i): i(i) {}
};

class B
{
    public:
    int i;
	B(int i): i(i) {}
    operator A()
    {
        std::cout << i << " is evaluated\n";
        return A(i);
    }
};


A operator* (const A& a, const A& b) {
	cout << "multiplication done\n";
	return A(a.i*b.i);
}

A operator/ (const A& a, const A& b) {
	cout << "division done\n";
	
	return A(a.i/b.i);
}
A operator+ (const A& a, const A& b) {
	return A(a.i + b.i);
}

ostream& operator<< (ostream& os, const A& a) {
	return os << a.i;
}

int main() {
	B a(3), b(4), c(2);
	cout << (a * b / c) << endl;
}
OUTPUT FROM TWO DIFFERENT COMPILERS:
3 is evaluated
4 is evaluated
multiplication done
2 is evaluated
division done
6

================================

2 is evaluated
4 is evaluated
3 is evaluated
multiplication done
division done
6
http://coliru.stacked-crooked.com/a/0a5baeb1a8c8c38f
As you can see operations are executed in order set by their priority. However individual operarands are evaluated in any order.
Basicly presedence and associativity only sets virtual parentheses. Evaluation of subbexpressions which do not depend on each other can happen in any order.

For example in this code division will be always evaluated last: it depends on value 2, so it should be evaluated after it evaluation ("read"), and it also depends on multiplication result, which depends on 4 and 2, so those should be evaluated before it.
the explanations i made at last post demonstrated what i wanted to say and didn't try to change the evaluation order you are talking about.

Evaluation order, indeed. In the
 a * b / c 

there are many things to evaluate:
A: the value of 'a'
B: the value of 'b'
C: the value of 'c'
D: the value of '*'
E: the value of '/'

Only the D and E have associativity, priority, precedence, order.
Only the order of D and E can be modified with parentheses.

Without parentheses:
* D and C must occur before E
* A and B must occur before D

There is no way to force order to the evaluation of A, B and C (unless you split the statement and use named temporaries). It is the undefined evaluation order of A, B and C that your original question and answers to it are about. Not the D and E.

Your original statement has 6 operators:
A: the value of 'i++'
B: the value of 'i++'
C: the value of '++i'
D: the value of '<<'
E: the value of '<<'
F: the value of '<<'

The order D E F is defined. The only thing known about A B C is that they have to occur latest just before the << that needs their return value.
@last 2 posts : i am with you completely, but i somehow noticed after many experiments the entity of the behaviour i wanted to ask about, regarding this code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
using namespace std;
class A {
public:
	int i;
	A(int i): i(i) {}
};
A operator* (A& a, A& b) {
	cout << "multiplication done\n";
	return A(a.i*b.i);
}
A operator/ (A& a, A& b) {
	cout << "division done\n";
	return A(a.i/b.i);
}
A operator+ (A& a, A& b) {
	cout << "addition done\n";
	return A(a.i + b.i);
}
A operator- (A& a, A& b) {
	cout << "subtraction done\n";
	return A(a.i - b.i);
}
ostream& operator<< (ostream& os, A& a) {
	return os << a.i;
}
void main() {
	A a(4), b(2);
	cout << a*b << a+b << a/b << a-b << endl;
}

the output in my compiler (visual studio 2015):

subtraction done
division done
addition done
multiplication done
8622

let us now from order of evaluation of values of a and b and let's talk about the << and the whole values after it.
regarding an operation which is after << operator like: a+b in: << a+b <<, not a alone, not b alone and not + alone but a+b as a whole:
my compiler as you see evaluated the ones on the right first, that is: (a-b) then (a/b) then (a+b) then (a*b), after that evaluated the << operator itself from left to right to display values of: (a*b) then (a+b) then (a/b) then (a-b).
and after many experiments i found that my compiler works like that usually (performs what is after << from right to left and performs << itself from left to right) i mean: regarding: cout << value1 << value2 << value3; it usually evaluates value3 then value2 then value1 and displays value1 then value2 then value3 (the displaying is normal and i am not questioning about it).
what i want to ask: is it just an incident that my compiler performs subtraction then division then addition then multiplication (that is in cout << value1 << value2 << value3; it evaluates value3 then value2 then value1) or this behaviour is dominant in c++ ?
Last edited on
is it just an incident that my compiler performs subtraction then division then addition then multiplication
Yes. This is an incident. AFAIK VS does not documents this behavior, therefore it is not guaranteed even for that compiler, much less for others. I have already posted example how different compilers can evaluate data differently.


Let me show my superior Paint skills: http://puu.sh/jBmYz/9b72f8cffa.png
This is the sequencing tree. Each pair of operations connected with line has a relationship: lower one is sequenced after upper one. Obviously relationship is transitive: if a is sequenced before b and b is sequenced before c, then a is sequenced before c.

If there is no direct relationship, then two operations can happen in any order.

So division should happen before last <<, but it can happen either before multiplication or after.

Also note that we evaluate a and b several times.
Compiler can combine those evaluation and use value it gets for all operations. Or might choose to not do that. Generally it will do what is permitted by language rules and enhances perfomance.

yes, another short example on this unspecified behaviour:
1
2
3
4
5
6
7
8
9
#include <iostream>
#include <string>
using namespace std;
string value1() { cout << "value1 called\n"; return "value1 displayed\n"; }
string value2() { cout << "value2 called\n"; return "value2 displayed\n"; }
string value3() { cout << "value3 called\n"; return "value3 displayed\n"; }
int main() {
cout << value1() << value2() << value3();
return 0;}

outputs:

value3 called
value2 called
value1 called
value1 displayed
value2 displayed
value3 displayed
Last edited on
Topic archived. No new replies allowed.