operator precedence in C++ expressions - c++

Program 1:
#include <iostream>
using namespace std;
int a = 5;
int fun1() {
a = 17;
return 3;
}
int main() {
// Even though C languages are left associative,
// this line of code evaluates fun1() first:
a = a + fun1();
// a = 17+3
printf("%d",a);
a = fun1()+a;
printf("\n%d",a);
return 0;
}
output:
20
20
Program 2:
int a = 10;
int fun(){
a= 15;
return 30;
}
int main(void) {
// whereas in this example, fun() is evaluated last:
int x = a + 10 + fun();
// x = 10 + 10 + 30
a= 10;
int y = fun() + 10 + a;
printf(" x = %d \n y = %d \n",x,y);
return 0;
}
output:
x = 50
y = 55
Why does program 1 evaluate fun1() first whereas in program 2 fun() is evaluated last when it is placed at the end of the expression?
From what I understand, C-based languages are left associative so why is program 1 behaving weird?

Historically, order of arguments evaluation of a function call was unspecified. That means that for the call
foo(bar(), baz());
it was left up to the compiler if it needs to call bar(), than baz(), or the other way around. Keep in mind that calling an operator is another case of a generic function call, i.e. baz() + bar() is semantically the same as operator+(baz(), bar()).
For practical purposes, compilers used to evaluate arguments from last to first, given the fact that this is the order of pushing arguments to the stack for many function call ABIs.

You mixed 2 concepts (it happens quite often though), let's look to expression:
a = b + c + d * e;
operator precedence and associativity means, that this expression is equal to
a = ( ( b + c ) + ( d * e ) );
but it does not mean for example, that d * e must be evaluated before b + c, just because * has higher precedence. Details can be found here order of evaluation
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.
emphasis is mine.

There are three separate concepts that frequently get confused:
Evaluation order, which determines in which order operands are evaluated.
This is usually left unspecified in the standard.
Precedence, which determines which of two operators is evaluated first.
For instance, in a + b * c, the multiplication is evaluated before the addition.
The evaluation order of the operands is not affected by precedence.
Associativity, which determines which operator of the same precedence is evaluated first.
For instance, << is left-associative; a << b << c is evaluated as (a << b) << c, while assignment is right-associative; a = b = c is a = (b = c).
The evaluation order of the operands is not affected by associativity either.

evaluation order of this type are not specified by standard. it is up to the compiler to do the optimization he is doing.

Related

Use of reference variables in C++ [duplicate]

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.

Why doesn't it short-circuit when you multiply the return value of a function by zero?

Consider a function like the below:
unsigned int fact(unsigned int i) {
if (i <= 1) { return 1; }
return i * fact(i-1);
}
If I were to instantiate a new variable unsigned int f such that f = 0 * fact(5), why does it not "short circuit"?
unsigned int fact(unsigned int i) {
std::cout << "a";
if (i <= 1) { return 1; }
return i * fact(i-1);
}
int main() {
unsigned int f = 0 * fact(5);
}
The output here is aaaaa. If f can only ever be zero, why would it call the function at all, supposing it knew the return type? Does it not evaluate left to right, see 0 * (unsigned int) and know the rvalue will be 0?
Short-circuit evaluation is mandatory for && (logical and), || (logical or) and ? (ternary operator). For the remaining operators it is an (optional) optimization.
The evaluation of fact(5) in the expression 0 * fact(5) can't be in general optimized away just because you know that the outcome of the whole expression is 0 since a call to fact() may introduce side effects (e.g., modify some global variable), so it must be called.
As said in this comment, a good compiler will optimize away the call to fact(5) if it can prove that there are no side effects.
Does it not evaluate left to right, see 0 * (unsigned int) and know the rvalue will be 0?
It could, and it would if the standard told it to.
But it doesn't.
Short-circuiting simply isn't a thing for multiplication. They could have made it a thing, but it would arguably have been confusing.
We're all used to f() || g() potentially skipping the call to g(), but would you really expect 0 * g() to do the same thing? Particularly since 0 is just one out of billions of possible integers? It would be an oddly specific feature. (By contrast true is one out of only two boolean values.)
This isn't about side effects, because the side effects of g() would be skipped by f() || g() if f() returns true. That's just how it is.
In practice, a compiler could elide the call to g() in 0 * g() if it knew that g() had no side-effects (so the program's behaviour wouldn't be changed), but that's not short-circuiting; that's "optimisation".

c++ spaces in operators , what are the rules

Does spaces have any meaning in these expressions:
assume:
int a = 1;
int b = 2;
1)
int c = a++ +b;
Or,
2)
int c = a+ ++b;
When I run these two in visual studio, I get different results. Is that the correct behavior, and what does the spec says?
In general, what should be evaluated first, post-increment or pre-increment?
Edit: I should say that
c =a+++b;
Does not compile on visual studio. But I think it should. The postfix++ seems to be evaluated first.
Is that the correct behavior
Yes, it is.
Postfix ++ first returns the current value, then increments it. so int c = a++ +b means compute the value of c as the sum between current a(take the current a value, and only after taking it, increment a) and b;
Prefix ++ first increments the current value, then returns the value already incremented, so in this case, int c = a+ ++b means compute c as the sum between a and the return of the next expression, ++b, which means b is first incremented, then returned.
In general, what should be evaluated first, post-increment or
pre-increment?
In this example, it is not about which gets evaluated first, it is about what each does - postfix first returns the value, then increments it; prefix first increments the value, then returns it.
Hth
Maybe it helps to understand the general architecture of how programs are parsed.
In a nutshell, there are two stages to parsing a program (C++ or others): lexer and parser.
The lexer takes the text input and maps it to a sequence of symbols. This is when spaces are handled because they tell where the symbols are. Spaces really matter at some places (like between int and c, to not confuse with the symbol intc) but not others (like between a and ++ because there is no ambiguity to separate them).
The first example:
int c = a++ +b;
gives the following symbols, each on its own row (implementations may do this in slightly different ways of course):
int
c
=
a
++
+
b
;
While in the other case:
int c = a+ ++b;
the symbols are instead:
int
c
=
a
+
++
b
;
The parser then builds a tree (Abstract Syntax Tree, AST) out of the symbols and according to some grammar. In particular, according to the C++ grammar, + as an addition has a lower precedence than the unary ++ operator (regardless of postfix or prefix). This means that the first example is semantically the same as (a++) + b while the second is like a+ (++b).
For your examples, the ASTs will be different, because the spaces already lead to a different output at the lexer phase.
Note that spaces are not required between ++ and +, so a+++b would theoretically be fine, but this is not recommended for readability. So, some spaces are important for technical reasons while others are important for us users to read the code.
Yes they should be different; the behaviour is correct.
There are a few possible sources for your confusion.
This question is not about "spaces in operators". You have different operators. If you were to remove the space, you would have a different question. See What is i+++ increment in c++
It's also not about "what should be evaluated first, post-increment or pre-increment". It's about understanding the difference between post-increment and pre-increment.
Both increment the variable to which they apply.
But the post-increment expression returns the value from before the increment.
Whereas the pre-increment expression returns the value after the increment.
I.e.
//Given:
int a = 1;
int b = 2;
//Post-increment
int c = a++ +b; =>
1 + 2; (and a == 2) =>
3;
//Pre-increment
int c = a+ ++b; =>
1 + 3; (and b == 3) =>
4;
Another thing that might be causing confusion. You wrote: a++ +b;. And you may be assuming that +b is the unary + operator. This would be an incorrect assumption because you have both left and right operands making that + a binary additive operator (as in x + y).
Final possible confusion. You may be wondering why:
in a++ +b the ++ is a post-increment operator applied to a.
whereas in a+ ++b it's a pre-increment operator applied to b.
The reason is that ++ has higher precedence than the binary additive +. And in both cases it would be impossible to apply ++ to +.

Why are VB.NET and C++ giving different results for same expression?

Consider the following snippets:
C++:
#include <iostream>
using namespace std;
int main()
{
int x = 10, y = 20;
y = x + (x=y)*0;
cout << y;
return 0;
}
which gives a result of 20, because the value of y is assigned to x since the bracket is executed first according to the Operator Precedence Table.
VB.NET:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim x As Integer = 10
Dim y As Integer = 20
y = x + (x = y) * 0
MsgBox(y)
End Sub
which instead gives a result of 10.
What is the reason for this difference?
What is the order of execution of operators in VB.NET?
Unlike in C++, VB.NET's = is not always an assignment. It can also be the equality comparison operator (== in C++) if it appears inside an expression. Therefore your two expressions are not the same. They are not even equivalent. The VB.NET code does not do what you might think it does.
First to your C++ code: Like you're saying, the assignment x=y happens first; thus your code is roughly equivalent to this: (It seems that was incorrect; see Jens' answer.) Since you end up with y being 20, it is likely that your C++ compiler evaluated your code as if you had written this:
int x = 10, y = 20;
x = y;
y = x + x*0; // which is equivalent to `y = 20 + 20*0;`, or `y = 20 + 0;`, or `y = 20;`
In VB.NET however, because the = in your subexpression (x=y) is not actually interpreted as an assignment, but as a comparison, the code is equivalent to this:
Dim x As Integer = 10
Dim y As Integer = 20
y = 10 + False*0 ' which is equivalent to `y = 10 + 0*0`, or `y = 10` '
Here, operator precedence doesn't even come into play, but an implicit type conversion of the boolean value False to numeric 0.
(Just in case you were wondering: In VB.NET, assignment inside an expression is impossible. Assignments must always be full statements of their own, they cannot happen "inline". Otherwise it would be impossible to tell whether a = inside an expression meant assignment or comparison, since the same operator is used for both.)
Your C++ snippet is undefined behavior. There is no sequence point between using x as the first argument and assigning y to x, so the compiler can evaluate the sub-expressions in any order. Both
First evaluate the left side: y = 10 + (x=y) * 0 -> y = 10 + (x=20) * 0 -> y = 10 + 20*0
First evaluate the right side: y = x + (x=20) * 0 -> y = 20 + 20 * 0
It is also generally a very bad style to put assignments inside expressions.
This answer was intended as a comment, but its length quickly exceeded the limit. Sorry :)
You are confusing operator precedence with evaluation order. (This is a very common phenomenon, so don't feel bad). Let me try to explain with a simpler example involving more familiar operators:
If you have an expression like a + b * c then yes, the multiplication will always happen before the addition, because the * operator binds tighter than + operator. So far so good? The important point is that C++ is allowed to evaluate the operands a, b and c in any order it pleases. If one of those operands has a side effect which affects another operand, this is bad for two reasons:
It may cause undefined behavior (which in your code is indeed the case), and more importantly
It is guaranteed to give future readers of your code serious headaches. So please don't do it!
By the way, Java will always evaluate a first, then b, then c, "despite" the fact that multiplication happens before addition. The pseudo-bytecode will look like push a; push b; push c; mul; add;
(You did not ask about Java, but I wanted to mention Java to give an example where evaluating a is not only feasible, but guaranteed by the language specification. C# behaves the same way here.)

Why the addtion of ++overloaded operation results into unexpted values?

See the code
#include<iostream.h>
#include<conio.h>
class A{
private:
int i;
public:
A()
{
i=10;
}
A operator++(int)
{
A tmp=*this;
i +=1;
return tmp;
}
display()
{
cout<<i;
}
};
int main()
{
A a,b;
b=a++ + a++;
cout<<endl<<b<<"\t"<<a;
return 0;
}
For the statement b = a++ + a++, the expected value we think will be 20,
But the above statement resulted into 21.
How?
Kindly help me out.
According to cppreference, your code is equals to b = (a++) + (a++)
So, computing it, we have:
a = 10;
tmp1 = a++;//tmp1 = 10, a = 11
tmp2 = a++;//tmp2 = 11, a = 12
b = tmp1 + tmp2 // 10 + 11 = 21
Also remember that constructions like b = a++ + a++; are very poor readable, so you should always use brackets, also it's always a good idea to avoid using increments and decrements like a++ in complex expressions. Readability is much better than showing that you know operator priorities.
As Charles pointed out ++ called on A object are function calls. Thus you first increment i from 10 to 11 and return 10, then in the second call you increment i from 11 to 12 and return 11. The you add 10 and 11 ending up with 21.
The first call increments a to 11 and returns 10. The second call increments a to 12 and returns 11. Sounds like 21 is correct.
That said, the order of evaluation (which ++ is "the first call") is unspecified (thanks JD), so using it twice in the same expression is generally not a good idea.
I shall render my answer in the form of a simple comparison.
Your code is:
b = a++ + a++;
I think you rather confused it with:
b = a + (a++)++;
Overloaded operators are just functions with funny names. They don't neccesarily behave the same as built-in ones. If you're tempted to do the same expression with an object of built-in type - don't, the behaviour would be undefined.
You haven't shown the definition of operator+ for A - I'll asume it's a free function. The expression b = a++ + a++; can then be rewritten as
b = operator+( a.operator++(0), a.operator++(0) );
Hope that helps make things clearer.
The two calls to postfix increment are indeterminately sequenced - that means we can't know which one will be called first. It doesn't matter in your case, since they're both called on the same object, but don't rely on any particular order - it need not be consistent, even during the same execution of the program.