Question

I have an if statement with one statement in its body, but with a condition formed of several OR'd expressions.

During execution, if the first expression in an OR'd condition is true, will the second still be evaluated??

i.e. Is it better to have the expressions OR'd, or to have each expression form a single condition for an else where the body of each else is the same?

e.g

if ((!x && y && z) || (x && !y && !z) || (x != y) {
    foo();

//vs

if (!x && y && z)
    foo();
else if (x && !y && !z)
    foo();
else if (x != y)
    foo();
Was it helpful?

Solution

No, if the left side of an OR (AND) evaluates to true (false), the right side is not evaluated. It's called short-circuiting and is a very well known feature of C.

You can check this by

int f () {
    printf("f!\n");
    return 1;
}

int g () {
    printf("g!\n");
    return 0;
}

int main () {
    if(f() || g())
      printf("hey\n");
}

This would print

 f!
 hey

OTHER TIPS

the first code is 'better', since when using || , the first evaluation that return true will end the evaluation of the condition. if you still wish to evaluate all the terms, use a single |

Short answer: NO
C short-circuits all if statements with the || and && logical operators. There's no way around that. In fact: C has no eager operators.

The reasoning behind this is, that if you want a single action performed in case any of 1, 2, 3,... cases were true, then there would be no need to evaluate all cases if just one of them had to be true. In other words, short-circuit evaluation is faster.
Therefore, your first snippet is the better option, provided it doesn't impede readability .

consider the following (pseudo-code):

if (is_alphabet_letter('a') || is_alphabet_letter('b') || is_alphabet_letter('c'))
    puts("Found letter of the roman alphabet");

This'll result in only 1 call to the is_alphabet_letter function, rather then three. As far as the resulting program is concerned, the above snippet evaluates to:

if (true /*|| jibberish, don't care*/)
    puts("...");

Whereas this:

if (is_alphabet_letter('a'))
   puts("");
else  if (is_alphabet_letter('b')
   puts("");
else  if (is_alphabet_letter('c')
   puts("");

Just adds clutter, and will -in all likelyhood- be optimized by the compiler to resemble something more like the first statement.
The same applies to &&, btw:

if (false && true && a_complex_function())

Will never result in a call to a_complex_function, simple because the first expression evaluates to false, and to check any of the remaining expressions is therefore pointless. C just moves on, either to the else block, or to the next statement.
That's why choosing the order of the expressions in an if block sometimes make a difference:

if (a_complex_function() && false)

will always call the function. Sometimes, that may be what you want, but sometimes it isn't, so it doesn't hurt to consider moving the more complicated expressions towards the end of the if statement.

The two cases will most likely yield the very same machine code, or something very close. So which one to pick is a matter of coding style.

I would say that if the operations are complex, so that they will not easily fit on one single line, then the if-else if is to prefer. Otherwise, if the operations are somewhat simple, the || version is probably to prefer. It is rather subjective though.

Advanced discussion about the inner workings of these operators follows. You may stop reading here if you aren't terribly interested about such things!


However, there are some details that make the two versions ever so slightly different. In both cases, each individual operand is implicitly promoted using type balancing. But in the case of ||, there is an extra implicit promotion taking place:

The result of (!x && y && z) is balanced against the result of (x && !y && !z). In the end, the result is of the type of the operand with biggest conversion rank.

Does it matter? I can't see how it would in this specific case. But lets say we have something like this:

uint8_t  x;
uint8_t  y;
uint32_t z;

And then we have an expression:

if( (x && y) || (x && z) )

// or

if(x && y)
{}
else if(x && z)
{}

Lets assume we are using a 8 or 16 bit CPU where int is 16 bits.

In the if-else case, the following happens:

  • x and y are both integer promoted from uint8_t to int, since they are small integer types.
  • The expression (int)x && (int)y is balanced. x && y is calculated on the type int and the result is of type int.
  • In the expression x && z, x is integer promoted as above, but not z, it is not a small integer type and remains uint32_t.
  • The expression (int)x && (uint32_t)z is balanced and then calculated on the type uint32_t. The result is of type uint32_t.
  • Thus x && y is always calculated on a 16 bit variable and x && z is always calculated on a 32 bit variable.

If we look at the || version, the same things happen. But then we have another, additional balancing: (uint16_t)first_result || (uint32_t)second_result. This balancing is enforced because of the || operator. Which means that if x==true and y==true, then result of the whole operation will be of type uint32_t.

But in the if-else version, the x && y type was always uint16_t. The || version introduced an obscure tight coupling between the type of x and the type of z.

Whether or not the compiler is able to efficiently optimize this || scenario, I have no idea. I would expect it to, but since the compiler can make no compile-time decisions about what the result of the whole expression will be, since it can't know if the operands are true or false, it might just end up executing it all on 32-bit types. And that is bad news if we had an 8 or 16 bit CPU, which will handle 32 bit number very inefficiently.

No, the double logic operators (&& and ||) will evaluate every argument one after the other until it finds one satisfying result.

In the case of &&, all the arguments will be evaluated until it finds a false, in which case the expression condition is false and the if code will not be evaluated.

In the case of ||, arguments will be evaluated until it finds a true, in which case the expression condition is true and the if code will be evaluated.

If you want all the elements of your expression to be evaluated, use the & and | operators. They will created a variable that will be ANDed or ORed by all the elements of your expression and only the final value of the variable will be used in the condition.

The result is the same, but with & and |, you're sure that all the expressions of your condition will be evaluated.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top