This is a pretty basic question, but I could not find a clear answer:
is it allowed to check that a pointer is not null and (&&) to also check one of its members value in the same if statement?
Rephrased: is the right part of the condition in the example below even evaluated if f is null?
I know this works in VS current version, but what I need to know is if this is allowed by the C++ standard (or if it's UB).
Also, if I write it as 2 separate if to make it more readable, can I expect the compiler to optimize it into a single if?
struct foo
{
bool bar;
};
void main(){
foo *f;
// DO THINGS
if (f != null && f->bar == true)
{
// DO THINGS
}
}
Edit: the question is different from this one because it's not obvious that it's simply a matter of order: the proof is I did not end on that SO answer when I googled my question.
...is it allowed to check that a pointer is not null and (&&) to also check one of its members value in the same if statement?
It's perfectly valid, it is not UB, the expression is evaluated from left to right, if the left part of the expression evaluates to false the right part is not evaluated. This is usually called operator short circuit.
The rationale is that if the first part is false, there is no possibilty of the whole expression being true, false && false is false, false && true is also false.
...if I write it as 2 separate if to make it more readable, can I expect the compiler to optimize it into a single if?
In light of the above answer, you wouldn't need two ifs, I would argue that it will not make your code more readable, I prefer the way you have it right know, in any case this is only my opinion. About the compiler, I wouldn't think that there will be much difference either way, as sampled in this live demo.
is it allowed to check that a pointer is not null and (&&) to also check one of its members value in the same if statement?
Yes.
is the right part of the condition in the example below even evaluated if f is null?
No.
what I need to know is if this is allowed by the C++ standard
Yes.
(or if it's UB)
No.
Also, if I write it as 2 separate if to make it more readable, can I expect the compiler to optimize it into a single if?
I would expect it. Seems like a trivial optimisation. Note that in cases where the && operator is overloaded (which never is in the case of pointers), such change can change the meaning of the program.
Standard quote (latest draft):
[expr.log.and]
The && operator groups left-to-right.
The operands are both contextually converted to bool.
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.
Related
I'm new to c++ and am curious how the compiler handles lazy evaluation of booleans. For example,
if(A == 1 || B == 2){...}
If A does equal 1, is the B==2 part ever evaluated?
No, the B==2 part is not evaluated. This is called short-circuit evaluation.
Edit: As Robert C. Cartaino rightly points out, if the logical operator is overloaded, short-circuit evaluation does not take place (that having been said, why someone would overload a logical operator is beyond me).
Unless the || operator is overloaded, the second expression will not be evaluated. This is called "short-circuit evaluation."
In the case of logical AND (&&) and logical OR (||), the second expression will not be evaluated if the first expression is sufficient to determine the value of the entire expression.
In the case you described above:
if(A == 1 || B == 2) {...}
...the second expression will not be evaluated because
TRUE || ANYTHING, always evaluates to TRUE.
Likewise,
FALSE && ANYTHING, always evaluates to FALSE, so that condition will also cause a short-circuit evaluation.
A couple of quick notes
Short circuit evaluation will not apply to overloaded && and || operators.
In C++, you are guaranteed that the first expression will be evaluated first. Some languages do not guarantee the order of evaluation and VB doesn't do short-circuit evaluation at all. That's important to know if you are porting code.
The B==2 part is not evaluated.
Be careful! Don't put something like ++B==2 over there!
C++ applies short circuiting to Boolean expression evaluation so, the B == 2 is never evaluated and the compiler may even omit it entirely.
The compiler handles this by generating intermediate jumps. For the following code:
if(A == 1 || B == 2){...}
compiled to pseudo-assembler, might be:
load variable A
compare to constant 1
if equal, jump to L1
load variable B
compare to constant 2
if not equal, jump to L2
L1:
... (complete body of if statement)
L2:
(code after if block goes here)
This is short-circuit evaluation, as James says. Lazy evaluation is something entirely different.
No it's not.
Same with &&, if one is wrong, it doesn't bother evaluating the other one.
B == 2 is never evaluated.
See Short-Circuit Evaluation for more information.
What is the computation order of the equal priority operands in C / C++ ?
For example in following piece of code:
if ( scanf("%c", &ch_variable) && (ch_variable == '\n') )
Can I be sure that 1st expression inside the IF statement is performed before the 2nd (i.e. the value of ch_variable compared, is a newly scanned one)?
Or is it somehow decided by compiler? And if so, how this decision is being made?
BTW, I usually use the following flags for compilation:
-std=c99 -O0 -pedantic -Wall -ansi
Can I be sure that 1st expression inside the IF statement is performed before the 2nd (i.e. the value of ch_variable compared, is a newly scanned one)?
Yes - the first expression (the scanf call) is evaluated first, and what's more the second doesn't happen at all if the scanf call returns 0 - see below. That's short circuit evaluation.
Broader discussion.
Read about the operator precedence at cppreference.com
Summarily - operators are arranged in groups with well-defined relative precedence (e.g. '*' has higher precendence than +, as per usage in mathematics), and left-to-right or right-to-left associativity (e.g. a + b + c is left associative and evaluated as (a + b) + c, but a = b = c is right-associative and evaluated as a = (b = c)).
In your code:
if (scanf("%c", &ch_variable) && (ch_variable == '\n') )
The ( and ) work as you'd expect - overriding any implicit precedence between && and == (but in this case the precedence is the same). && is therefore uncontested, and as a short-circuit operator it ensures its left argument is converted - if necessary - to boolean (so if scanf returns 0 it's deemed false, otherwise true), then if and only if that's true does it evaluate the right-hand-side argument, and only if they're both true does the if statement run the following statement or {} statement block.
This has nothing to do with "priority" (operator precedence), but with the order of evaluation of sub-expressions.
The && operator is a special case in C, as it guarantees order of evaluation from left to right. There is a sequence point between the evaluation of the left operand and the right operand, meaning that the left operation will always be executed/evaluated first.
Many C operators do not come with this nice guarantee, however. Imagine the code had been like this:
if ( (scanf("%c", &ch_variable)!=0) & (ch_variable == '\n') )
This is obfuscated code but it logically does the same thing as your original code. With one exception: the & operator behaves as most operators in C, meaning there are no guarantees that the left operand will get evaluated before the right one. So my example has the potential of evaluating ch_variable before it has been given a valid value, which is a severe bug.
The order of evaluation of such sub-expressions is unspecified behavior, meaning that the compiler is free to evaluate any side first. It doesn't need to document what it will do and it doesn't even need to pick the same side consistently between compilations, or even pick the same side consistently throughout the program.
The language was deliberately designed this way to allow compilers to optimize the code in the best possible way, from case to case.
Yes, absolutely, anything involving && and || (except if you use operator&& or operator|| - which is one of the main reasons NOT to use these operators) is "strict short cutting" - in other words, if the overall outcome of the result can be determined, the rest is not evaluated, and the order is strictly left to right - always, by the language standard. [Of course, if the compiler can be SURE it's completely safe, it may reorder things, but that is part of the "as-if" definition of the standard - if the compiler behaves "as-if" it is doing it the way the standard says].
Beware that:
if(scanf("%c", &ch_variable) && scanf("%c", &second_variable))
{
...
}
else
{
...
}
may not have set "second_variable" at all in the else part, so it's unsafe to use it at this point.
I would aos use scanf("%c", &ch_variable) > 0 instead - as it could return -1 at EOF, which is true in your case, without an intermediate 0 return value...
It's guaranteed that the first expression is evaluated before the second one.
See Is short-circuiting logical operators mandated? And evaluation order? for a citation of the standard.
Note that if you overload the && operator, the whole expression is equivalent to a function call. In that case both expressions will be evaluated unconditionally (i.e. even if the first expression would be some "falsy" value...).
The order that the operands are evaluated is defined in this case, and it is left-to-right.
This goes for both C and C++.
For a reference of this, see for example page 99 of the C standard: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf.
Hence, in terms of order-of-evaluation, your code will do what you want it to. But it does have some other problems; see the post comments for this.
Please consider the following block of C++-code.
call * pCall; // Make a pointer to private variable call.
pCall = NULL; // We are sure that it is a null pointer.
aMemberFuntionThatMayChangeTheValueOfpCall();
if (pCall != NULL and pCall->isDelivered() == false){
doSomething();
}
I would like to execute some lines of code, here represented by doSomething(), if and only if pCall is not a null pointer and pCall->isDelivered() is false.
However, I read that the order of evaluation is unspecified. So theoretically the compiler may evaluate pCall->isDelivered() first, and run into a run time exception. However, in the debugging sessions it seems to evaluate the and-operator left to right. Can someone please shine a light on this? I don't want any failures of the code when it gets into a production environment or when it gets executed on another machine.
Of course it is possible to make it into two nested if-statements, but this makes the source far more unreadable because I need this kind of code multiple times.
Can anyone tell me how to do this evaluation in one if-statement such that there is no misevaluation?
Your and operator is more commonly written in C++ as &&, but they are both the same "logical and" operator. For this operator the order of evaluation is specified and evaluation is executed from left to right, guaranteed. (Otherwise millions of existing programs would fail).
The exception - not applicable to your code - is when the && operator is overloaded. In this case the left-to-right rule does not work. BTW it is a main reason why it is recommended not to overload this operator.
Your code below will work (I've changed 'and' to '&&' and added parentheses):
if ( (pCall != NULL) && (pCall->isDelivered() == false) ) {
doSomething();
}
because the logical-AND && will 'short circuit'; i.e. if the first expression is false, the second will not be evaluated. Evaluation order is from left to right in this case.
The following relates to the Miscosoft C++ compiler in VS2013:
Logical operators also guarantee evaluation of their operands from
left to right. However, they evaluate the smallest number of operands
needed to determine the result of the expression. This is called
"short-circuit" evaluation. Thus, some operands of the expression may
not be evaluated. For example, in the expression x && y++ the second
operand, y++, is evaluated only if x is true (nonzero). Thus, y is not
incremented if x is false (0).
I have read in a lot of places but I really can't understand the specified behavior in conditionals.
I understand that in assignments it evaluates the first operand, discards the result, then evaluates the second operand.
But for this code, what it supposed to do?
CPartFile* partfile = (CPartFile*)lParam;
ASSERT( partfile != NULL );
bool bDeleted = false;
if (partfile,bDeleted)
partfile->PerformFileCompleteEnd(wParam);
The partfile in the IF was an unnecessary argument, or it have any meaning?
In this case, it is an unnecessary expression, and can be deleted without changing the meaning of the code.
The comma operator performs the expression of the first item, discards the results, then evaluates the result as the last expression.
So partfile,bDeleted would evaulate whatever partfile would, discard that result, then evaluate and return bDeleted
It's useful if you need to evaluate something which has a side-effect (for example, calling a method). In this case, though, it's useless.
For more information, see Wikipedia: Comma operator
bool bDeleted = false;
if (partfile,bDeleted)
partfile->PerformFileCompleteEnd(wParam);
Here, the if statement evaluates partfile,bDeleted, but bDelete is always false, so the expression fails to run. The key question is "what's that all about?". The probable answer is that someone temporarily wanted to prevent the partfile->PerformFileCompleteEnd(wParam); statement from running, perhaps because it was causing some problem or they wanted to ensure later code reported errors properly if that step wasn't performed. So that they're remember how the code used to be, they left the old "if (partfile)" logic there, but added a hardcoded bDeleted variable to document that the partfile->Perform... logic had effectively been "deleted" from the program.
A better way to temporarily disable such code is probably...
#if 0
if (partfile)
partfile->PerformFileCompleteEnd(wParam);
#endif
...though sometimes I try to document the reasoning too...
#ifndef DONT_BYPASS_FILE_COMPLETE_PROCESSING_DURING_DEBUGGING
if (partfile)
partfile->PerformFileCompleteEnd(wParam);
#endif
...or...
if (partFile, !"FIXME remove this after debugging")
partfile->PerformFileCompleteEnd(wParam);
The best choice depends on your tool set and existing habits (e.g. some editors highlight "FIXME" and "TODO" in reverse video so it's hard to miss or grey out #if 0 blocks; you might have particular strings your source-control checkin warns about; preprocessor defines only in debug vs release builds can prevent accidental distribution etc.).
partfile is evaluated, then bDeleted is evaluated and used as the test. Since evaluation of partfile does not have any side effects, removing it from the conditional has no effect.
The comma operator is a rather obscure feature of C/C++. It should not be confused with the comma in initialising lists (ie: int x, int y; ) nor with function call parameter separation comma (ie: func(x, y) ).
The comma operator has one single purpose: to give the programmer a guaranteed order of evaluation of an expression. For almost every operator in C/C++, the order of evaluation of expressions is undefined. If I write
result = x + y;
where x and y are subexpressions, then either x or y can be evaluated first. I cannot know which, it's up to the compiler. If you however write
result = x, y;
the order of evaluation is guaranteed by the standard: left first.
Of course, the uses of this in real world applications are quite limited...
I'm new to c++ and am curious how the compiler handles lazy evaluation of booleans. For example,
if(A == 1 || B == 2){...}
If A does equal 1, is the B==2 part ever evaluated?
No, the B==2 part is not evaluated. This is called short-circuit evaluation.
Edit: As Robert C. Cartaino rightly points out, if the logical operator is overloaded, short-circuit evaluation does not take place (that having been said, why someone would overload a logical operator is beyond me).
Unless the || operator is overloaded, the second expression will not be evaluated. This is called "short-circuit evaluation."
In the case of logical AND (&&) and logical OR (||), the second expression will not be evaluated if the first expression is sufficient to determine the value of the entire expression.
In the case you described above:
if(A == 1 || B == 2) {...}
...the second expression will not be evaluated because
TRUE || ANYTHING, always evaluates to TRUE.
Likewise,
FALSE && ANYTHING, always evaluates to FALSE, so that condition will also cause a short-circuit evaluation.
A couple of quick notes
Short circuit evaluation will not apply to overloaded && and || operators.
In C++, you are guaranteed that the first expression will be evaluated first. Some languages do not guarantee the order of evaluation and VB doesn't do short-circuit evaluation at all. That's important to know if you are porting code.
The B==2 part is not evaluated.
Be careful! Don't put something like ++B==2 over there!
C++ applies short circuiting to Boolean expression evaluation so, the B == 2 is never evaluated and the compiler may even omit it entirely.
The compiler handles this by generating intermediate jumps. For the following code:
if(A == 1 || B == 2){...}
compiled to pseudo-assembler, might be:
load variable A
compare to constant 1
if equal, jump to L1
load variable B
compare to constant 2
if not equal, jump to L2
L1:
... (complete body of if statement)
L2:
(code after if block goes here)
This is short-circuit evaluation, as James says. Lazy evaluation is something entirely different.
No it's not.
Same with &&, if one is wrong, it doesn't bother evaluating the other one.
B == 2 is never evaluated.
See Short-Circuit Evaluation for more information.