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.
Related
I know that C/C++ uses the short-circuit evaluation to evaluate the expression of boolean. For example, C/C++ will definitely evaluate the operand a before the operand b in the expression a && b, if a is false, b won't be evaluated.
Besides, I know that things like 5==6 may be totally ignored by the compiler because it is a constant expression, which can be evaluated at compile time.
But I don't know if b && 0 can be optimized by compiler? Can compiler say: OK, the evaluation of 0 is much easier than the evaluation of b, and b hasn't any side effect, so I decide to change b && 0 into 0 && b to evaluate 0 first.
There are two independent problems involved in your question. The first is that when a compiler "sees" that the if condition is always false (due to && 0), it can completely throw away the corresponding branch. Example translation unit:
bool f(int);
int main()
{
if (f(1) && 0)
return 1;
}
With enabled optimizations, there will be very likely no machine code generated for the branch. However, the f(1) expression must be still evaluated at runtime, since the compiler cannot prove that the f(1) call has no observable behavior.
Machine code: https://godbolt.org/z/sEMrfh
On the contrary, if the compiler could prove that f(1) had no observable behavior, it could eliminate its call away. This has nothing to do with the order of evaluation, but with the as-if rule instead. Demo translation unit:
static bool f(int i)
{
int j = i + 1;
return true;
}
int main()
{
if (f(1) && 0)
return 1;
}
Machine code: https://godbolt.org/z/scs3je
The && and || operators guarantee left-to-right evaluation. Evaluation meaning that the compiler has to check the operand for side effects and if any are present, it must execute those. And if the left operand of && evaluates to zero, it will not evaluate the right one.
Consider if(func() && 0) { do_stuff(); }. Even though the && expression can never be true, the function must still be executed. The compiler isn't going to do some strange re-ordering such as 0 && func(), it will rather just replace the whole expression with func();, removing the if and do_stuff() both.
In general, the compiler is specifically not allowed to re-order the evaluation or execution of the operands of && and ||; they have a so-called sequence point between evaluation of the left and the right operand. Which in turn allows code like (ptr=malloc(...)) && (*ptr = x) to be well-defined and not access a null pointer in case malloc fails.
if(a && b)
{
do something;
}
is there any possibility to evaluate arguments from right to left(b -> a)?
if "yes", what influences the evaluation order?
(i'm using VS2008)
With C++ there are only a few operators that guarantee the evaluation order
operator && evaluates left operand first and if the value is logically false then it avoids evaluating the right operand. Typical use is for example if (x > 0 && k/x < limit) ... that avoids division by zero problems.
operator || evaluates left operand first and if the value is logically true then it avoids evaluating the right operand. For example if (overwrite_files || confirm("File existing, overwrite?")) ... will not ask confirmation when the flag overwrite_files is set.
operator , evaluates left operand first and then right operand anyway, returning the value of right operand. This operator is not used very often. Note that commas between parameters in a function call are not comma operators and the order of evaluation is not guaranteed.
The ternary operator x?y:z evaluates x first, and then depending on the logical value of the result evaluates either only y or only z.
For all other operators the order of evaluation is not specified.
The situation is actually worse because it's not that the order is not specified, but that there is not even an "order" for the expression at all, and for example in
std::cout << f() << g() << x(k(), h());
it's possible that functions will be called in the order h-g-k-x-f (this is a bit disturbing because the mental model of << operator conveys somehow the idea of sequentiality but in reality respects the sequence only in the order results are put on the stream and not in the order the results are computed).
Obviously the value dependencies in the expression may introduce some order guarantee; for example in the above expression it's guaranteed that both k() and h() will be called before x(...) because the return values from both are needed to call x (C++ is not lazy).
Note also that the guarantees for &&, || and , are valid only for predefined operators. If you overload those operators for your types they will be in that case like normal function calls and the order of evaluation of the operands will be unspecified.
Changes since C++17
C++17 introduced some extra ad-hoc specific guarantees about evaluation order (for example in the left-shift operator <<). For all the details see https://stackoverflow.com/a/38501596/320726
The evaluation order is specified by the standard and is left-to-right. The left-most expression will always be evaluated first with the && clause.
If you want b to be evaluated first:
if(b && a)
{
//do something
}
If both arguments are methods and you want both of them to be evaluated regardless of their result:
bool rb = b();
bool ra = a();
if ( ra && rb )
{
//do something
}
In this case, since you're using &&, a will always be evaluated first because the result is used to determine whether or not to short-circuit the expression.
If a returns false, then b is not allowed to evaluate at all.
Every value computation and side effect of the first (left) argument of the built-in logical AND operator && and the built-in logical OR operator || is sequenced before every value computation and side effect of the second (right) argument.
Read here for a more exhaustive explanation of the rules set:
order evaluation
It will evaluate from left to right and short-circuit the evaluation if it can (e.g. if a evaluates to false it won't evaluate b).
If you care about the order they are evaluated in you just need to specify them in the desired order of evaluation in your if statement.
The built-in && operator always evaluates its left operand first. For example:
if (a && b)
{
//block of code
}
If a is false, then b will not be evaluated.
If you want b to be evaluated first, and a only if b is true, simply write the expression the other way around:
if (b && a)
{
//block of code
}
if(a && b)
{
do something;
}
is there any possibility to evaluate arguments from right to left(b -> a)?
if "yes", what influences the evaluation order?
(i'm using VS2008)
With C++ there are only a few operators that guarantee the evaluation order
operator && evaluates left operand first and if the value is logically false then it avoids evaluating the right operand. Typical use is for example if (x > 0 && k/x < limit) ... that avoids division by zero problems.
operator || evaluates left operand first and if the value is logically true then it avoids evaluating the right operand. For example if (overwrite_files || confirm("File existing, overwrite?")) ... will not ask confirmation when the flag overwrite_files is set.
operator , evaluates left operand first and then right operand anyway, returning the value of right operand. This operator is not used very often. Note that commas between parameters in a function call are not comma operators and the order of evaluation is not guaranteed.
The ternary operator x?y:z evaluates x first, and then depending on the logical value of the result evaluates either only y or only z.
For all other operators the order of evaluation is not specified.
The situation is actually worse because it's not that the order is not specified, but that there is not even an "order" for the expression at all, and for example in
std::cout << f() << g() << x(k(), h());
it's possible that functions will be called in the order h-g-k-x-f (this is a bit disturbing because the mental model of << operator conveys somehow the idea of sequentiality but in reality respects the sequence only in the order results are put on the stream and not in the order the results are computed).
Obviously the value dependencies in the expression may introduce some order guarantee; for example in the above expression it's guaranteed that both k() and h() will be called before x(...) because the return values from both are needed to call x (C++ is not lazy).
Note also that the guarantees for &&, || and , are valid only for predefined operators. If you overload those operators for your types they will be in that case like normal function calls and the order of evaluation of the operands will be unspecified.
Changes since C++17
C++17 introduced some extra ad-hoc specific guarantees about evaluation order (for example in the left-shift operator <<). For all the details see https://stackoverflow.com/a/38501596/320726
The evaluation order is specified by the standard and is left-to-right. The left-most expression will always be evaluated first with the && clause.
If you want b to be evaluated first:
if(b && a)
{
//do something
}
If both arguments are methods and you want both of them to be evaluated regardless of their result:
bool rb = b();
bool ra = a();
if ( ra && rb )
{
//do something
}
In this case, since you're using &&, a will always be evaluated first because the result is used to determine whether or not to short-circuit the expression.
If a returns false, then b is not allowed to evaluate at all.
Every value computation and side effect of the first (left) argument of the built-in logical AND operator && and the built-in logical OR operator || is sequenced before every value computation and side effect of the second (right) argument.
Read here for a more exhaustive explanation of the rules set:
order evaluation
It will evaluate from left to right and short-circuit the evaluation if it can (e.g. if a evaluates to false it won't evaluate b).
If you care about the order they are evaluated in you just need to specify them in the desired order of evaluation in your if statement.
The built-in && operator always evaluates its left operand first. For example:
if (a && b)
{
//block of code
}
If a is false, then b will not be evaluated.
If you want b to be evaluated first, and a only if b is true, simply write the expression the other way around:
if (b && a)
{
//block of code
}
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().
void main(void)
{
int x,y,z;
x=y=z=1;
z = x && y && ++z;//is this fine?
}
I have lately started reading about sequence points stuffs but I cannot figure out whether the above sample of code is fine or not. I know the && operator introduces a sequence point so I am not very sure about the behavior of the expression z = x && y && ++z. Someone please tell me the correct answer.
In C++ 03.
void main(void)
{
int x,y,z;
x=y=z=1; // Seq1 at ;
z = x && y && ++z;//is this fine? // Seq2 at ;
}
NB: Note that there are sequence points at the operator && but then those are not relevant in this example.
Fine!. In general, may be or may be Not. Depends on the values of x and y. In your specific case, it is not fine. This code has the potential to have something called undefined behavior.
If z++ is evaluated (as in your example because x and y are 1), then the scalar variable 'z' is modified more than once in the expression between two sequence points Seq1 and Seq2 (see below). It is important to note that the assignment operator does not introduce any sequence point.
$5/4- "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.53) Between the previous
and next sequence point a scalar
object shall have its stored value
modified at most once by the
evaluation of an expression.
Furthermore, the prior value shall be
accessed only to determine the value
to be stored. The requirements of this
paragraph shall be met for each
allowable ordering of the
subexpressions of a full expression;
otherwise the behavior is undefined."
In C++0x
Will update it once I myself understand the details of the discussion referred to by #litb. For now, I am just striking it off
In C++0X however, as I understand, there is no concept of sequence points. This expression is fine and does not invoke undefined behavior. This is because the effect of ++ on 'z' is sequenced before the side effect of assignment on 'z'.
$1.9/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, the
behavior is undefined.
$3.9/9 - "Arithmetic types (3.9.1),
enumeration types, pointer types,
pointer to member types (3.9.2),
std::nullptr_t, and cv-qualified
versions of these types (3.9.3) are
collectively called scalar types."
Note that in the expression 'z = z++;' where z is a scalar variable, the side effects on 'z' due to assignment operator and postfix operator++ are unsequenced (neither of them is sequenced before the other).
Thanks #Prasoon for giving valuable inputs to refine this post from original version
A simple way to know if that line is fine or not is let the compiler check that. For example, gcc has the -Wsequence-point option (enabled by -Wall) for checking if there's undefined behavior because of lack of sequence points.
Your program
int main(void)
{
int x,y,z;
x=y=z=1;
z = x && y && ++z;/*is this fine?*/
return 0;
}
produces this warning:
x.c: In function 'main':
x.c:6:5: warning: operation on 'z' may be undefined
Yes, it will compile.
But if you are asking about logical bugs:
1) the && operator introduces a sequence point because it could terminate the evaluation of the expression when it knows for sure the final result (in this case a 0 value can terminate the evaluation), so it won't even reach to the ++z part if x or y is zero.
2) because the && operator is a logical one, the result will always be 0 or 1, and I doubt that this is what you wanted.