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
Related
This question already has answers here:
Is short-circuiting logical operators mandated? And evaluation order?
(7 answers)
Safety concerns about short circuit evaluation [duplicate]
(4 answers)
Closed 9 years ago.
I have a char pointer initialized to NULL at the beginning of the program, further in the program the char* is used in a function call where it might get pointed to a string of char s and it might point to null char, and it might remain untouched.
So is the following statement correct, it should be if the expressions are evaluated from left to right. If not then strlen ( charpointer ) is undefined behavior, if charpointer == NULL
if ( charpointer == NULL || strlen ( charpointer ) == 0 )
So, do they get evaluated from left to right ? Is this the correct way to go about checking like this ?
The order of evaluation for || is from left to right, as Eric mentions this is a special property of || and &&, most operators do not enforce left to right evalation. It will not evaluate the right expression if the left one succeeds, from the C99 draft standard section 6.5.14 paragraph 4:
Unlike the bitwise | 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 unequal to 0, the second operand is not evaluated.
The C++ draft standard has similar language in section 5.15 paragraph 1.
The characteristics of the evaluation process have absolutely nothing to do with if statement. The evaluation is dictated by the properties of the expression itself. The fact that it is used in if makes no difference whatsoever.
In your case the expression in question is
charpointer == NULL || strlen ( charpointer ) == 0
Its behavior is primaruly defined by the properties of || operator, which is guaranteed to be evaluated from left to right, with first operand's evaluation being sequenced before the second operand's evaluation, and with "premature completion" ("short-circuiting") in case the first operand evaluates to true.
That means that the controlling expression in your original post is perfecly safe.
Order of evaluation is, as indicated by others from left to right but it is important to realize that evaluation stops at the point where the truth (or lack thereof) of the logical expression can be determined.
This is the case for both || and &&.
This is particularly important because you CANNOT assume that the entire expression will be evaluated so if any of the components of the logical expression have side-effects (such as function calls, increments, assignments, etc.,) they do not all have to be executed.
To test charpointer to see if it is a null.
if (charpointer == NULL) { // etc.
If you want to test if charponter is pointing to a NULL char, then:
if ((charpointer != NULL) && (strlen(charpointer) == 0) { // etc.
You can combine these statements as:
if (charpointer == NULL) {
} else {
if (strlen(charpointer) == 0) { // etc.
or as:
if ((charpointer != NULL) && (strlen(charpointer) == 0)) {// etc.
or you can rely on short-circuiting which is what your code is doing. But, the test for charpointer == NULL MUST come first because the expression is evaluated left to right.
Finally after you have written a fair amount of c code, you learn that:
if (! charpointer) { // etc.
is the same as testing it for being equal to NULL. So, just to be fancy and write unreadable code, then:
if (!charpointer || !(strlen(charpointer)) { // etc.
order of evaluation from left to right.
In your case if loop will check first condition from left to right. If first condition fails it will go and check second condition from left to right.
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().
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.
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.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Is short-circuiting boolean operators mandated in C/C++? And evaluation order?
Is there any defined by standard or math rules order of eveluating boolean sentences? For example:
if (firstTrue && secondTrue)
{
}
can I be sure that firstTrue will be checked first?
Yes. && and || are short circuiting operators. The order of evaluation of operands is well defined (left to right).
&& is also a sequence point.
So writing if( ++i && i) { } is perfectly fine.
ISO C++03 (5.14/1) says:
The && operator groups left-to-right. The operands are both implicitly converted to type bool (clause 4). The result is true if both operands are true and false otherwise. Unlike &, && guarantees left-to-right evaluation: the second operand is not evaluated if the first operand is false.
EDIT: (After seeing the comment)
ISO C++03 (Section 1.9/18) says
In the evaluation of each of the expressions
a && b
a || b
a ? b : c
a , b
using the built-in meaning of the operators in these expressions (5.14, 5.15, 5.16, 5.18), there is a sequence point after the evaluation of the first expression.
Yes firstTrue will be evaluated first. In fact, if firstTrue is false, the secondTrue will not even be evaluated. This is called short circuiting.
Check out this article: http://en.wikipedia.org/wiki/Short-circuit_evaluation
The same happens with ||. If the first argument to || is true, the second will not be evaluated.
It is not about boolean sentences. It is about specific operators in these "sentences" (logical expressions, actually)
The built-in && operator (as well as ||) are special: they guarantee that the left-hand side is evaluated before the right-hand size. They have a sequence point between the LHS and RHS evaluations. And they don't evaluate the RHS if the result is pre-determined by the LHS. Aside from this (and some other operators that have similar sequencing properties), there are no guarantees about the order of evaluation of logical expressions, or any other expressions.
The above applies to built-in && and || operators. Overloaded && and || operators are not special in any way.