I've just read that order of evaluation and precedence of operators are different but related concepts in C++. But I'm still unclear how those are different but related?.
int x = c + a * b; // 31
int y = (c + a) * b; // 36
What does the above statements has to with order of evaluation. e.g. when I say (c + a) am I changing the order of evaluation of expression by changing its precedence?
The important part about order of evaluation is whether any of the components have side effects.
Suppose you have this:
int i = c() + a() * b();
Where a and b have side effects:
int global = 1;
int a() {
return global++;
}
int b() {
return ++global;
}
int c() {
return global * 2;
}
The compiler can choose what order to call a(), b() and c() and then insert the results into the expression. At that point, precedence takes over and decides what order to apply the + and * operators.
In this example the most likely outcomes are either
The compiler will evaluate c() first, followed by a() and then b(), resulting in i = 2 + 1 * 3 = 5
The compiler will evaluate b() first, followed by a() and then c(), resulting in i = 6 + 2 * 2 = 10
But the compiler is free to choose whatever order it wants.
The short story is that precedence tells you the order in which operators are applied to arguments (* before +), whereas order of evaluation tells you in what order the arguments are resolved (a(), b(), c()). This is why they are "different but related".
"Order of evaluation" refers to when different subexpressions within the same expression are evaulated relative to each other.
For example in
3 * f(x) + 2 * g(x, y)
you have the usual precedence rules between multiplication and addition. But we have an order of evaluation question: will the first multiplication happen before the second or the second before the first? It matters because if f() has a side effect that changes y, the result of the whole expression will be different depending on the order of operations.
In your specific example, this order of evaluation scenario (in which the resulting value depends on order) does not arise.
As long as we are talking about built-in operators: no, you are not changing the order of evaluation by using the (). You have no control over the order of evaluation. In fact, there's no "order of evaluation" here at all.
The compiler is allowed to evaluate this expression in any way it desires, as long as the result is correct. It is not even required to use addition and multiplication operations to evaluate these expressions. The addition and multiplication only exist in the text of your program. The compiler is free to totally and completely ignore these specific operations. On some hardware platform, such expressions might be evaluated by a single atomic machine operation. For this reason, the notion of "order of evaluation" does not make any sense here. There's nothing there that you can apply the concept of "order" to.
The only thing you are changing by using () is the mathematical meaning of the expression. Let's say a, b and c are all 2. The a + b * c must evaluate to 6, while (a + b) * c must evaluate to to 8. That's it. This is the only thing that is guaranteed to you: that the results will be correct. How these results are obtained is totally unknown. The compiler might use absolutely anything, any method and any "order of evaluation" as long as the results are correct.
For another example, if you have two such expressions in your program following each other
int x = c + a * b;
int y = (c + a) * b;
the compiler is free to evaluate them as
int x = c + a * b;
int y = c * b + x - c;
which will also produce the correct result (assuming no overflow-related problems). In which case the actual evaluation schedule will not even remotely look like something that you wrote in your source code.
To put it short, to assume that the actual evaluation will have any significant resemblance to what you wrote in the source code of your program is naive at best. Despite popular belief, built-in operators are not generally translated in their machine "counterparts".
The above applies to built-in operators, again. Once we start dealing with overloaded operators, things change drastically. Overloaded operators are indeed evaluated in full accordance with the semantic structure of the expression. There's some freedom there even with overloaded operators, but it is not as unrestricted as in case of built-in operators.
The answer is may or may not.
The evaluation order of a, b and c depends on the compiler's interpretation of this formula.
Consider the below example:
#include <limits.h>
#include <stdio.h>
int main(void)
{
double a = 1 + UINT_MAX + 1.0;
double b = 1 + 1.0 + UINT_MAX;
printf("a=%g\n", a);
printf("b=%g\n", b);
return 0;
}
Here in terms of math as we know it, a and b are to be computed equally and must have the same result. But is that true in the C(++) world? See the program's output.
I want to introduce a link worth reading with regard to this question.
The Rules 3 and 4 mention about sequence point, another concept worth remembering.
Related
I thought I understand how sequence points work in C++, but this GeeksQuiz question puzzled me:
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;
cout << f(p, p) << endl;
return 0;
}
The “correct” answer to this question says it prints 6561. Indeed, in VS2013 it does. But isn't it UB anyway because there is no guarantee which will be evaluated first: f(x, c) or x. We get 6561 if f(x, c) is evaluated first: the whole thing turns into five recursive calls: the first four (c = 5, 4, 3, 2) continue on, the last one (c = 1) terminates and returns 1, which amounts to 9 ** 4 in the end.
However, if x was evaluated first, then we'd get 6 * 7 * 8 * 9 * 1 instead. The funny thing is, in VS2013 even replacing f(x, c) * x with x * f(x, c) doesn't change the result. Not that it means anything.
According to the standard, is this UB or not? If not, why?
This is UB.
n4140 §1.9 [intro.execution]/15
Except where noted, evaluations of
operands of individual operators and of subexpressions of individual
expressions are unsequenced. [...] If a side effect on a scalar object
is unsequenced relative to [...] value computation using the value of
the same scalar object [...] the behavior is undefined.
Multiplicative operators don't have sequencing explicitly noted.
This is UB
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.
Will this code always result in the same result?
return c * (t /= d) * t * t + b;
So I expect:
return ((c * (t / d) ^ 3) + b);
But I am not sure if the compiler can also interpret it as:
return ((c * t * t * (t / d)) + b)
I have searched in the C standard but could not find an answer,
I know that x = x++ is undefined but here I am not sure because of the () around the t /= d which I think force the compiler to first calculate that statement.
I have searched in the C standard but could not find an answer
The thing you're searching for is the sequence point.
Your expression
c * (t /= d) * t * t + b
doesn't contain any sequence points, so the sub-expressions may be evaluated in any relative order.
NOTE that this applies to C, since you mentioned that in the question. You've also tagged the related-but-very different language C++, which has different rules. Luckily, in this case, they give exactly the same result.
The relevant text from the 2014-11-19 working draft PDF:N4296 is
1.9 Program Execution [intro.execution]
...
14 Every value computation and side effect associated with a full-expression is sequenced before every value
computation and side effect associated with the next full-expression to be evaluated.
15 Except where noted, evaluations of operands of individual operators and of subexpressions of individual
expressions are unsequenced. [ Note: In an expression that is evaluated more than once during the execution
of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be
performed consistently in different evaluations. — end note ] The value computations of the operands of an
operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar
object is unsequenced relative to either another side effect on the same scalar object or a value computation
using the value of the same scalar object, and they are not potentially concurrent (1.10), the behavior is
undefined. [ Note: The next section imposes similar, but more complex restrictions on potentially concurrent
computations. — end note ]
So the logic in C++ is that unless things are explicitly sequenced (eg, by a ; separating two full expressions), then they can happen in any order.
As the (second) highlighted section mentions, when two un-sequenced sub-expressions modify the same object (or one modifies and one reads), the behaviour is undefined.
The above expression, with parenthesis making the order of operations explicit, is as follows:
return ((((c * (t /= d)) * t) * t) + b);
The problem here, however, is that there is no sequence point in this expression. So any of the subexpressions can be evaluated in any order.
For example, the compiler may choose to evaluate the value of t once, then use the original value each place it appears. Conversely, it may first evaluate t /= d which modifies t, then use this modified value anyplace else it appears.
In short, because you are both reading and writing a variable in a single expression without a sequence point, you invoke undefined behavior.
The following statement:
return c * (t /= d) * t * t + b;
invokes undefined behaviour in C (and I believe in C++ too). This is because t is evaluated twice (counting the (t /= d) subexpression) despite of an unsequenced side effect (produced by the compound assignment operator), that is affecting object represented by t variable.
The moment when you encounter UB is the one you should stop thinking about "proper" value of the expression. There is none, because anything is possible, including turning off your PC.
The recent versions of gcc and clang with -Wall may tell you that expression is suspected of invoking UB. Here, the warnings are:
warning: operation on 't' may be undefined [-Wsequence-point]
warning: unsequenced modification and access to 't' [-Wunsequenced]
What is the return value of f(p,p), if the value of p is
initialized to 5 before the call? Note that the first parameter is
passed by reference, whereas the second parameter is passed by value.
int f (int &x, int c) {
c = c - 1;
if (c==0) return 1;
x = x + 1;
return f(x,c) * x;
}
Options are:
3024
6561
55440
161051
I try to explain:
In this code, there will be four recursive calls with parameters (6,4), (7,3), (8,2) and (9,1). The last call returns 1. But due to pass by reference, x in all the previous functions is now 9. Hence, the value returned by f(p,p) will be 9 * 9 * 9 * 9 * 1 = 6561.
This question is from the competitive exam GATE, (see Q.no.-42). The answer key is given by GATE "Marks to all" (means there is no option correct.) key set-C, Q.no.-42. Somewhere explained as:
In GATE 2013 marks were given to all as the same code in C/C++ produces undefined behavior. This is because * is not a sequence point in C/C++. The correct code must replace
return f(x,c) * x;
with
res = f(x,c);
return res * x;
But the given code works fine. Is GATE's key wrong? Or is really the mistake with the question?
return f(x,c) * x;
The result of this operation depends on the order in which the two things are evaluated. Since you cannot predict the order they'll be evaluated, you cannot predict the result of this operation.
C++03 chapter 5:
Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual
expressions, and the order in which side effects take place, is unspecified.
So in the case of f(x,c) * x, the order of evaluation of the operands is unspecified, meaning that you can't know if the left or right operand will get evaluated first.
Your code has unspecified behavior, meaning that it will behave in a certain defined manner which is only known to the compiler. The programmer can't know what the code will do, only that it will either evaluate the left operand first, or the right operand first. The compiler is even allowed to change the order of evaluation on a case-to-case basis, for optimization purposes.
If the order of evaluation matters, you need to rewrite the code. Code relying on unspecified behavior is always a bug, possibly a quite subtle one which will not immediately surface.
Unspecified behavior is different from undefined behavior, which would mean that anything could happen, including the program going haywire or crashing.
The C++11 standard (5.17, expr.ass) states that
In all cases, the assignment is sequenced after the value computation
of the right and left operands, and before the value computation of
the assignment expression. With respect to an
indeterminately-sequenced function call, the operation of a compound
assignment is a single evaluation
Does this mean, that the expression:
int a = 1, b = 10;
int c = (a+=1) + (b+=1);
if ( c == 10+1+1+1 ) {
printf("this is guaranteed");
} else {
printf("not guaranteed");
}
will always evaluate to c==23?
The expression
int c = (a+=1) + (b+=1);
(edit: added the missing brackets, I think this is what you intended)
has the following subexpressions
(1) a+=1
(2) b+=1
(3) (1)+(2)
(4) c = (3)
The order in which (1) and (2) are evaluated is unspecified, the compiler is free to choose any order it likes.
Both (1) and (2) must be evaluated before the compiler can evaluate (3).
(3) must be evaluated before the compiler can evaluate (4).
Now as the order of evaluation of (1) and (2) does not matter, the overall result is well defined, your code will always yield 13 and print "this is now standard". Note that is has always been this way, this is not new with C++11.
This has always been guaranteed, and the sequenced before rules
(or the sequence point rules in pre-C++11) aren't need to
determine this. In C++, each (sub-)expression has two important
effects in the generated code: it has a value (unless it is of
type void), and it may have side effects. The sequenced
before/sequence point rules affect when the side effects are
guaranteed to have taken place; they have no effect on the value
of the sub-expressions. In your case, for example, the value
of (a += 1) is the value a will have after the assignment,
regardless of when the actual assignment takes place.
In C++11, the actual modification of a is guaranteed to take
place before the modification of c; in pre C++11, there was no
guarantee concerning the order. In this case, however, there is
no way a conforming program could see this difference, so it
doesn't matter. (It would matter in cases like c = (c += 1),
which would be undefined behavior in pre-C++11.)
In your example the compiler shall issue an error because the priority of the addition operator is higher than priority of the assignment operator. So at first 1 + b will be calculated and then there will be an attempt to assign 1 to expression ( 1 + b ) but ( 1 + b ) is not an lvalue.
When a expression is evaluated in C/C++, does it follow BODMAS [Bracket open Division Multiply Addition Substraction] rule? If not then how they are evaluated?
EDIT: More clearly, If the following expression is evaluated according to BODMAS rule,
(5 + 3)/8*9
First what is in brackets is processed.
8/8*9.
Then Division is done.
1*9
And then multiplication and so on.
There are far more operators than that. You can find a precedence tables for C++ and C.
But yes, you'll find it respects that. (Though I'm not sure it's exactly what you've said...)
There are two answers to this question.
One is that C++ does follow standard mathematical precedence rules, which you refer to as BODMAS. You can see the order in which C++ associates all its operators here.
However, if any of the expressions involved in the operation have side effects, then C++ is not guaranteed to evaluate them in what one might consider to be standard mathematical order. That's sort of an advanced topic, however.
Other people have given you links to operator precedence lists. These are well and good. However, if you need to look at an operator precedence table to determine what your code tells computers to do, please take pity on your code's maintainers (including future you) and just use parentheses. It makes your intention much clearer and saves time and heartache in the long run.
C++: http://msdn.microsoft.com/en-us/library/126fe14k.aspx
C#: http://msdn.microsoft.com/en-us/library/aa691323(VS.71).aspx
C applies the operators in arithmetic expressions in a precise sequence determined by the following rules of operator precedence, which are generally the same as those in algebra:
Operators in expressions contained within pairs of parentheses are evaluated first. Parentheses are said to be at the “highest level of precedence.” In cases of nested, or embedded, parentheses, such as
( ( a + b ) + c )
the operators in the innermost pair of parentheses are applied first.
Multiplication, division and remainder operations are applied next. If an expression contains several multiplication, division and remainder operations, evaluation proceeds from left to right. Multiplication, division and remainder are said to be on the same level of precedence.
Addition and subtraction operations are evaluated next. If an expression contains several addition and subtraction operations, evaluation proceeds from left to right. Addition and subtraction also have the same level of precedence, which is lower than the precedence of the multiplication, division and remainder operations.
The assignment operator (=) is evaluated last.
I found an expression that doesn’t follow “BODMAS”. Here is my c program for your reference
#include <stdio.h>
int main() {
int a = 6;
int b = 4;
int c = 2;
int result;
result = a - b + c; // 4
printf("%d \n", result);
result = a + b / c; // 8
printf("%d \n", result);
result = (a + b) / c; // 5
printf("%d \n", result);
return 0;
}