2

I always dare NOT to code like this:

void func( some_struct* ptr ) {
    if ( ptr != nullptr && ptr->errorno == 0 )
        do something...
};

instead I always do like this:

void func( some_struct* ptr ) {
    if ( ptr != nullptr )
        if ( ptr->errorno == 0 )
            do something...
};

because I'm afraid that the evaluation order of logical operator && is un-specified in C++ standard, even though commonly we could get right results with almost all of nowdays compilers. In a book, 2 rules let me want to get known exactly about it.

My question is : Without overloading, is the evaluation order of logical operator "&&" and "||" definite?

Sorry about my ugly English, I'm a Chinese. and I apologize if there is a duplicated topic, because I can't finger out correct key-words to search with. Thanks anyway!

Leon
  • 1,489
  • 1
  • 12
  • 31

3 Answers3

2

Yes, it's guaranteed for built-in logical AND operator and logical OR operator by the standard.

(emphasis mine)

[expr.log.and]/1

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.

[expr.log.or]/1

The || operator groups left-to-right. The operands are both contextually converted to bool. The result is true if either of its operands is true, and false otherwise. Unlike |, || guarantees left-to-right evaluation; moreover, the second operand is not evaluated if the first operand evaluates to true.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
1

Evaluation order for && and || is left to right.

Means in this case if (condition-1 && condition-2), then compiler will first check condition-1. If condition-1 is true then it will go to check next condition. But if condition-1 if false. It will return false as in && one false condition means result is false

Sameway in case of if (condition-1 || condition-2), compiler will first check condition-1. If it is true then it will return true. Because if ||, if one condition is true, then result is true. No need to check next conditions. But if it is false it will check next condition...

thisisjaymehta
  • 614
  • 1
  • 12
  • 26
  • I know, I meant to say that the short-circuiting operators check conditions from left-to-right and not right-to-left. As can be seen here [link](https://learn.microsoft.com/en-us/cpp/cpp/cpp-built-in-operators-precedence-and-associativity?view=vs-2019) – thisisjaymehta Nov 17 '19 at 04:50
  • 1
    The term "evaluation order" covers that, and it's in the question. Please edit your answer. – Keith Thompson Nov 17 '19 at 04:54
  • Is this correct now? – thisisjaymehta Nov 17 '19 at 04:59
  • Yes that is now correct, although "*No need to check next conditions.*" still makes it sound as if that was a sufficient condition for the short-circuiting rule to apply e.g. also for other operators, which is not the case. – walnut Nov 17 '19 at 05:07
0

Those operators have fixed evaluation rules that you can rely on.

You can safely use code like this:

if (op1 && op2)

With &&, both operands are needed to result to true in order for it to be true, if one of them is false then it short circuits, meaning that further evaluation of the && stops and it returns false. In short words, if the first operand is false then the second operand will not be evaluated since the operator will return false immediately.

For the case of || it will short circuit if at least one of its operands its true. Therefore, if the first operand is true then it will not evaluate the second operand because the operator returns true automatically.

This means that code like this: if (op1 && op2) is equivalent to:

if (op1)
{
    if (op2)
    {
        //some code
    }
}

And code like this if (op1 || op2) is the same as:

if (op1)
{
    //some code
}
else if (op2)
{
    //same code
}

Check these to know more about order of evaluation, operator precedence and logical operators.

Javier Silva Ortíz
  • 2,864
  • 1
  • 12
  • 21
  • 2
    "*the evaluation order is well defined.*": That seems wrong or misleading. In most cases the evaluation order of operands is *not* specified in C++. – walnut Nov 17 '19 at 04:53
  • 3
    "*For any deterministic language, such as C++, the evaluation order is well defined.*" -- That's not true in general. Even in C++, the evaluation order of the operands of *most* operators is *not* well defined. The `&&` and `||` operators happen to be a special case, and the order of operation and short-circuit semantics are guaranteed only because the language explicitly says so. – Keith Thompson Nov 17 '19 at 04:53
  • @JavierSilvaOrtíz For most operators the deterministic rule is that the evaluation order is unspecified (indeterministic), so that is a misleading way to talk about it, see also the first sentence in your links: "*Order of evaluation of any part of any expression, including order of evaluation of function arguments is unspecified (with some exceptions listed below).*" A program could randomly give different results for expressions that behave differently depending on the evaluation order. – walnut Nov 17 '19 at 15:44
  • `&&` and `||` are the exceptions. Replace them with `&` or `|` and `a` and `b` by compound expressions and the result may be either of multiple possibilities. – walnut Nov 17 '19 at 15:45
  • `int f() { static int i=0; return i++; } int main() { std::cout << f()-f(); }` The program can print either `1` or `-1`. In practice a compiler will of course choose either one of the orders and deterministically stick with it, but the standard does not require that. – walnut Nov 17 '19 at 16:04
  • @uneven_mark now I'm certain I was confusing the compiler implementation and the language specs. Thanks. By the way, I got `-1` in VS, Intel++ and GCC-arm, in which have you got `1`? – Javier Silva Ortíz Nov 17 '19 at 16:18
  • @JavierSilvaOrtíz I have not tested it and I don't know whether any current compiler does print `1`, but the point is that the compilers are free to decide without informing you. E.g. if the calculation in `f` would be more complicated, the optimizer may decide that evaluation in a certain order is faster and choose that or it might not. You cannot rely on the result that any particular (or many particular) compiler (version) is giving you. – walnut Nov 17 '19 at 16:22
  • [Here](https://godbolt.org/z/yABJN8) is a variation where I know that GCC and Clang differ in behavior. – walnut Nov 17 '19 at 16:27