Can I use x on both sides of a boolean expression when I post-increment it on the left side?
The line in question is:
if(x-- > 0 && array[x]) { /* … use x … */ }
Is that defined through the standard? Will array[x] use the new value of x or the old one?
It depends.
If && is the usual short-circuiting logical operator, then it's fine because there's a sequence point. array[x] will use the new value.
If && is a user (or library) defined overloaded operator, then there is no short-circuit, and also no guarantee of a sequence point between the evaluation of x-- and the evaluation of array[x]. This looks unlikely given your code, but without context it is not possible to say for sure. I think it's possible, with careful definition of array, to arrange it that way.
This is why it's almost always a bad idea to overload operator&&.
By the way, if ((x > 0) && array[--x]) has a very similar effect (again, assuming no operator overloading shenanigans), and in my opinion is clearer. The difference is whether or not x gets decremented past 0, which you may or may not be relying on.
Yes, it is well defined. && introduces a sequence point.
Related
This question already has answers here:
Is short-circuiting logical operators mandated? And evaluation order?
(7 answers)
Closed 9 years ago.
I have seen a particular style of code that according to me is dangerous and should be avoided, but I have seen it so many times in lot of places, that I am confused whether or not I am missing something.
int a[100];
/* Some code later */
for(i =0; (i < 100 && a[i] != 0); i++)
:
:
In the above code it is possible that the expression (i < 100 && a[i] != 0) is evaluated from right to left, in that case when i == 100, we are going out of bounds of the array 'a'.
Can someone explain whether or not this is safe code
The order of evaluation or arguments is well defined for &&, it cannot be changed.
#1 coupled with short circuiting makes this perfectly safe.
References:
C++03 Standard:
Section 5: Expressions, Para 4:
except where noted [e.g. special rules for && and ||], 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.
C99 Standard:
Section 6.5:
The grouping of operators and operands is indicated by the syntax.72) Except as specified later (for the function-call (), &&, ||, ?:, and comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified.
Note: Emphasis mine.
I think you can count on short-circuit evaluation not to access a[i] when i < 100 is false.
It is not possible that (i < 100 && a[i] != 0) is evaluated from right to left. && and || are explicitly defined as evaluating their left argument first, and their right argument only if necessary.
"In the above code it is possible that the expression (i < 100 && a[i] != 0) is evaluated from right to left..."
No, it is not possible, neither in C nor in C++. In both languages this expression is guaranteed to be evaluated from left to right. And if the first part is false, the second part is guaranteed not to be evaluated.
So, the code is perfectly safe from out-of-bounds access.
&& and || are evaluated left to right as every one said. You might want to consider following link for further information
http://en.cppreference.com/w/cpp/language/operator_precedence
I was wondering whether the access to x in the last if below here is undefined behaviour or not:
int f(int *x)
{
*x = 1;
return 1;
}
int x = 0;
if (f(&x) && x == 1) {
// something
}
It's not undefined behavior as operator && is a sequence point
It is well defined.
Reference - C++03 Standard:
Section 5: Expressions, Para 4:
except where noted [e.g. special rules for && and ||], 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.
While in,
Section 1.9.18
In the evaluation of the following expressions
a && b
a || b
a ? b : c
a , b
using the built-in meaning of the operators in these expressions, there is a sequence point after the evaluation of the first expression (12).
It is defined. C/C++ do lazy evaluation and it is defined that first the left expression will be calculated and checked. If it is true then the right one will be.
No, because && defines an ordering in which the lhs must be computed before the rhs.
There is a defined order also on ||, ?: and ,. There is not on other operands.
In the comparable:
int x = 0;
if (f(&x) & x == 1) {
// something
}
Then it's undefined. Here both the lhs and rhs will be computed and in either order. This non-shortcutting form of logical and is less common because the short-cutting is normally seen as at least beneficial to performance and often vital to correctness.
It is not undefined behavior. The reason depends on two facts, both are sufficient for giving defined behavior
A function call and termination is a sequence point
The '&&' operator is a sequence point
The following is defined behavior too
int f(int *x) {
*x = 1;
return 1;
}
int x = 0;
if (f(&x) & (x == 1)) {
// something
}
However, you don't know whether x == 1 evaluates to true or false, because either the first or the second operand of & can be evaluated first. That's not important for the behavior of this code to be defined, though.
It's not undefined, but it shouldn't compile either, as you're trying to assign a pointer to x (&x) to a reference.
&& will be evaluated from left to right (evaluation will stop, if the left side evaluates false).
Edit: With the change it should compile, but will still be defined (as it doesn't really matter if you use a pointer or reference).
It will pass the address of the local variable x in the caller block as a parameter to f (pointer to int). f will then set the parameter (which is a temporary variable on the stack) to address 1 (this causes no problem) and return 1. Since 1 is true, the if () will move on to evaluate x == 1 which is false, because x in the main block is still 0.
The body of the if block will not be executed.
EDIT
With your new version of the question, the body will be executed, because after f() has returned, x in the calling block is 1.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Safety concerns about short circuit evaluation
What does the standard say about evaluating && expressions - does it guarantee that evaluation of parameters will stop at the first false?
E.g.:
Foo* p;
//....
if ( p && p->f() )
{
//do something
}
is the f() guaranteed not to be called if p == NULL?
Also, is the order of evaluation guaranteed to be the order of appearence in the clause?
Might the optimizer change something like:
int x;
Foo* p;
//...
if ( p->doSomethingReallyExpensive() && x == 3 )
{
//....
}
to a form where it evaluates x==3 first? Or will it always execute the really expensive function first?
I know that on most compilers (probably all) evaluation stops after the first false is encountered, but what does the standard say about it?
What does the standard say about evaluating && expressions - does it guarantee that evaluation of parameters will stop at the first false?
Yes. That is called short-circuiting.
Also, is the order of evaluation guaranteed to be the order of appearence in the clause?
Yes. From left to right. The operand before which the expression short-circuited doesn't get evaluated.
int a = 0;
int b = 10;
if ( a != 0 && (b=100)) {}
cout << b << endl; //prints 10, not 100
In fact, the above two points are the keypoint in my solution here:
Find maximum of three number in C without using conditional statement and ternary operator
In the ANSI C standard 3.3.13:
Unlike the bitwise binary & operator, the && operator guarantees
left-to-right evaluation; there is a sequence point after the
evaluation of the first operand. If the first operand compares equal
to 0, the second operand is not evaluated.
There is an equivalent statement in the C++ standard
&& (and ||) establish sequence points. So the expression on the left-hand side will get evaluated before the right-hand side. Also, yes, if the left-hand side is false/true (for &&/||), the right-hand side is not evaluated.
What does the standard say about evaluating && expressions - does it guarantee that evaluation of parameters will stop at the first false?
Also, is the order of evaluation guaranteed to be the order of appearence in the clause?
5.14/1. Unlike &, && guarantees left-to-right evaluation: the second operand is not evaluated if the first operand is false.
This only works for the standard && operator, user defined overloads of operator && don't have this guarantee, they behave like regular function call semantics.
Might the optimizer change something like:
if ( p->doSomethingReallyExpensive() && x == 3 )
to a form where it evaluates x==3 first?
An optimizer may decide to evaluate x == 3 first since it is an expression with no side-effects associated if x is not modified by p->doSomethingReallyExpensive(), or even evaluate it after p->doSomethingReallyExpensive() already returned false. However, the visible behavior is guaranteed to be the previously specified: Left to right evaluation and short-circuit. That means that while x == 3 may be evaluated first and return false the implementation still has to evaluate p->doSomethingReallyExpensive().
If an expression evaluates multiple && operators, and does not evaluate any operators of lower precedence (eg. ||, ?:), will the expression evaluate to 0 as soon as one of the &&s return 0, or will it finish evaluating the remaining &&s?
For example,
q=0; w=1; e=1; r=1;
if(q && w && r && e) {}
Will this if() evaluate to false as soon as q && w evaluates to 0 (since the remaining && must all evaluate to 0 regardless of the right hand operators)?
Yes, evaluation will terminate early ("short circuit") as soon as a false expression is encountered. There is one exception to this: if the && operator has been overloaded for the relevant types of arguments. This is strongly discouraged and extremely rare, but could happen.
Yes, it does do short-circuit evaluation, for built-in types. Custom types where you've overloaded && or || won't have short-circuiting performed, which can cause subtle bugs.
Others have already stated the answer (i.e. "yes").
I will answer to add an example of one particularly idiomatic usage of this:
if ((p != NULL) && (*p == 42))
{
/* Do something */
}
This would have to be written in a much clumsier manner if short-circuiting didn't happen.
Note that you can also use this in a Perl-esque manner, e.g.:
someCondition && doSomething();
so doSomething() only gets called if someCondition is true. But this only compiles if doSomething() returns a type that can be converted to bool, and it's not considered idiomatic C++. (Note also that this technique doesn't compile in C.)
I recently came across something that I thought I understood right off the bat, but thinking more on it I would like understanding on why it works the way it does.
Consider the code below. The (x-- == 9) is clearly getting evaluated, while the (y++ == 11) is not. My first thought was that logical && kicks in, sees that the expression has already become false, and kicks out before evaluating the second part of the expression.
The more I think about it, the more I don't understand why this behaves as it does. As I understand it, logical operators fall below increment operations in the order of precedence. Shouldn't (y++ == 11) be evaluated, even though the overall expression has already become false?
In other words, shouldn't the order of operations dictate that (y++ == 11) be evaluated before the if statement realizes the expression as a whole will be false?
#include <iostream>
using namespace std;
int main( int argc, char** argv )
{
int x = 10;
int y = 10;
if( (x-- == 9) && (y++ == 11) )
{
cout << "I better not get here!" << endl;
}
cout << "Final X: " << x << endl;
cout << "Final Y: " << y << endl;
return 0;
}
Output:
Final X: 9
Final Y: 10
logical operators fall below increment operations in the order of
precedence.
Order of precedence is not order of execution. They're completely different concepts. Order of precedence only affects order of execution to the extent that operands are evaluated before their operator, and order of precedence helps tell you what the operands are of each operator.
Short-circuiting operators are a partial exception even to the rule that operands are evaluated before the operator, since they evaluate the LHS, then the operator has its say whether or not to evaluate the RHS, maybe the RHS is evaluated, then the result of the operator is computed.
Do not think of higher-precedence operations "executing first". Think of them "binding tighter". ++ has higher precedence than &&, and in the expression x ++ && y ++, operator precedence means that the ++ "binds more tightly" to y than && does, and so the expression overall is equivalent to (x++) && (y++), not (x++ && y) ++.
Shouldn't (y++ == 11) be evaluated, even though the overall expression has already become false?
No: the && and || operators short-circuit: they are evaluated left-to-right and as soon as the result of the expression is known, evaluation stops (that is, as soon as the expression is known to be false in the case of a series of &&, or true in the case of a series of ||)(*).
There is no sense in doing extra work that doesn't need to be done. This short-circuiting behavior is also quite useful and enables the writing of terser code. For example, given a pointer to a struct-type object, you can test whether the pointer is null and then dereference the pointer in a subsequent subexpression, for example: if (p && p->is_set) { /* ... */ }.
(*) Note that in C++, you can overload both the && and the || for class-type operands and if you do, they lose their short-circuiting property (it is generally inadvisable to overload && and || for this reason).
Precedence and associativity do not specify the order in which the operations are actually performed. They specify how operations are grouped: that is, in the following expression:
x && y++
...the lower precedence of && says that it is grouped as if it was:
x && (y++)
rather than as
(x && y)++
In your expression, the relative precedence of && and ++ do not matter, because you have separated those operators with parentheses anyway.
Grouping (and therefore precedence and associativity) specify what value each operator is operating on; but it specifies nothing about when it does so.
For most operators, the order in which the operations are performed is unspecified - however, in the case of && it is specified to evaluate the left hand operand first, then only evaluate the right hand operand if the result of the left hand operand was non-zero.
No. Order of precedence simply decides whether you get this:
A && B
(with A being x-- == 9 and B being y++ == 11) or
A == B == C
(with A being x--, B being 9 && y++, and C being 11).
Obviously, we're dealing with the first case. Short circuiting fully applies; if A is true, then B is not evaluated.
The conditional operators evaluate left-to-right and stop as soon as the result is known (an AND with a falsity or an OR with a true value).
C standard does not dictate any particular order of expression evaluation in if. So behavior will be compiler specific and using this style of coding not portable. You face that problem because incrementing/decrementing of value is post operation, but standard says as post operation of expression where variable is used. So if a compiler considers that your expression is just single variable usage as x or y, then you will see one result. If a compiler thinks that expression is entire if expression evaluation, then you will see other result. I hope it helps.