views:

877

answers:

11

I'd like to know if someone knows the way a compiler would interpret the following code:

#include <iostream>
using namespace std;

int main() {
 cout << (true && true || false && false) << endl; // true
}

Is this true because && has a higher precedence than || or because || is a short-circuit operator (in other words, does a short circuit operator disregard all subsequent expressions, or just the next expression)?

Update

If people believe that it's precedence, can you tell me why the following code produces true as well?

#include <iostream>
using namespace std;

bool infiniteLoop () {
    while (true);
    return false;
}

int main() {
    cout << (true && true || infiniteLoop() && infiniteLoop()) << endl; // true
}

Update #2

I've simplified the code in the second example and will attempt to explain my understanding of the second example's execution (and why I believe the expressions are evaluated in left-to-right order with && having equal precedence to ||).

Step-by-step:

  1. First &&: true && true evaluates to true
  2. First ||: left side true has been evaluated in step 1, || short-circuits entire expression as true

I believe this to be the answer because if && had precedence over ||, both && expressions would be evaluated before the || has a chance to short-circuit.

Think about the expression:

5 * 3 + 5 * 7

If * has higher precedence, both 5 * 3 and 5 * 7 are evaluated before the addition operator. Both * operators would have to be evaluated before the + operator. Applied to my example, both && operators would have to be evaluated before the || operator if it were true that && has higher precedence.

Therefore, && and || have the same precedence and are evaluated left-to-right.

If someone has a different understanding, it would be greatly appreciated to back up the assertion with code that can be compiled and verified.

+29  A: 

&& has a higher precedence than ||

AngelLeliel
Is there a reference to the C++ standard where this can be found?
Andrew
http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B
Caladain
That was in answer to Andrew :-)
Caladain
@Andrew: Since you said "standard", no; the standard isn't free and so isn't available anywhere (unless you find scraps of it around the internet). You can, however, download the [C++0x draft](http://stackoverflow.com/tags/c%2b%2b0x/info), which doesn't change C++ in this regard. However, with something as "common" as precedence you can be confident almost any site, though non-authoritative, will have the correct information.
GMan
Alf P. Steinbach
+7  A: 

&& does indeed have a higher precedence.

Ignacio Vazquez-Abrams
+17  A: 

(true && true || false && false) is evaluated with && having higher precedence.

TRUE && TRUE = True

FALSE && FALSE = False

True || False = True

Update:

1&&1||infiniteLoop()&&infiniteLoop()

Why does this produce true in C++?

Like before, lets break it apart. && has higher precedence that || and boolean statements short circuit in C++.

1 && 1 = True.

When a bool value is converted to an integer value, then

false -> 0
true -> 1

The expression evaluates this (true) && (true) statement, which short circuits the ||, which prevents the infinite loops from running. There's a lot more compiler Juju going on, so this is a simplistic view of the situation which is adequate for this example.

In a NON-short circuited environment, That expression would hang forever because both sides of the OR would be "evaluated" and the right side would hang.

If you're confused about the precedence, this is how things would evaluate in your original post if || had higher precedence than &&:

1st.) True || False = True
2nd.) True && 1st = True
3rd.) 2nd && false = false
Expression = False;

I can't remember if it goes right to left, or left to right, but either way the result would be the same. In your second post, if || had higher precendence:

1st.) 1||InfLoop();  Hang forever, but assuming it didn't
2nd.) 1 && 1st;
3rd.) 2nd && InfLoop(); Hang Forever

tl;dr: It's still precedence that's making the &&'s be evaluated first, but the compiler short circuits the OR as well. In essence, the compiler groups the order of operations like this (SIMPLISTIC VIEW, put down the pitchforks :-P)

1st.) Is 1&&1 True?
2nd.) Evaluate if the Left side of the operation is true, 
      if so, skip the second test and return True,
      Otherwise return the value of the second test(this is the OR)
3rd.) Is Inf() && Inf() True? (this would hang forever since 
      you have an infinite loop)

Update #2: "However, this example proves && DOES NOT have precedence, as the || is evaluated before the second &&. This shows that && and || have equal precedence and are evaluated in left-to-right order."

"If && had precedence it would evaluate the first && (1), then the second && (infinite loops) and hang the program. Since this does not happen, && is not evaluated before ||."

Let's cover these in detail.

We're talking about two distinct things here. Precedence, which determines the Order of Operations, and Short Circuiting, which is a compiler/language trick to save processor cycles.

Let's cover Precedence first. Precedence is short hand for "Order of Operations" In essence, given this statement: 1 + 2 * 3 in which order should the operations be grouped for evaluation?

Mathematics clearly defines the order of operations as giving multiplication higher precedence than addition.

1 + (2 * 3) = 1 + 2 * 3
2 * 3 is evaluated first, and then 1 is added to the result.
* has higher precedence than +, thus that operation is evaluated first.

Now, lets transition to boolean expressions: (&& = AND, || = OR)

true AND false OR true

C++ gives AND a higher precedence than OR, thus

(true AND false) OR true
true AND false is evaluated first, and then 
      used as the left hand for the OR statement

So, just on precedence, (true && true || false && false) will be operated on in this order:

((true && true) || (false && false)) = (true && true || false && false)
1st Comparison.) true && true
2nd Comparison.) false && false
3rd Comparison.) Result of 1st comparison || Result of Second

With me thus far? Now lets get into Short Circuiting: In C++, Boolean statements are what's called "short circuited". This means that the compiler will look at a given statement a choose the "best path" for evaluation. Take this example:

(true && true) || (false && false)
There is no need to evaluate the (false && false) if (true && true) 
equals true, since only one side of the OR statement needs to be true.
Thus, the compiler will Short Circuit the expression.  Here's the compiler's
Simplified logic:
1st.) Is (true && true) True?
2nd.) Evaluate if the Left side of the operation is true, 
      if so, skip the second test and return True,
      Otherwise return the value of the second test(this is the OR)
3rd.) Is (false && false) True? Return this value

As you can see, if (true && true) is evaluated TRUE, then there isn't a need to spend the clock cycles evaluating if (false && false) is true.

C++ Always short Circuts, but other languages provide mechanisms for what are called "Eager" operators.

Take for instance the programming language Ada. In Ada, "AND" and "OR" are "Eager" Operators..they force everything to be evaluated.

In Ada (true AND true) OR (false AND false) would evaluate both (true AND true) and (false AND false) before evaluating the OR. Ada Also gives you the ability to short circuit with AND THEN and OR ELSE, which will give you the same behavior C++ does.

I hope that fully answers your question. If not, let me know :-)

Update 3: Last update, and then I'll continue on email if you're still having issues.

"If short-circuiting the || operator occurs and short-circuits the execution of the second && expression, that means the || operator was executed BEFORE the second && operator. This implies left-to-right execution for && and || (not && precedence)."

Let's look at then this example:

(false && infLoop()) || (true && true) = true (Put a breakpoint in InfLoop and it won't get hit)
false && infLoop() || true && true = true  (Put a breakpoint in InfLoop and it won't get hit)
false || (false && true && infLoop()) || true = false (infLoop doesn't get hit)

If what you were saying was true, InfLoop would get hit in the first two. You'll also notice InfLoop() doesn't get called in the third example either.

Now, lets look at this:

(false || true && infLoop() || true);

Infloop gets called! If OR had higher precendence than &&, then the compiler would evaluate:

(false || true) && (infLoop() || true) = true;
(false || true) =true
(infLoop() || true = true (infLoop isn't called)

But InfLoop gets called! This is why:

(false || true && infLoop() || true);
1st Comparison.) true && InfLoop() (InfLoop gets called)
2nd Comparison.) False || 1st Comp (will never get here)
3rd Comparison.) 2nd Comp || true; (will never get here)

Precendece ONLY sets the grouping of operations. In this, && is greater than ||.

true && false || true && true gets grouped as
(true && false) || (true && true);

The Compiler Then comes along and determines what order it should execute the evaluation in to give it the best chance for saving cycles.

Consider: false && infLoop() || true && true
Precedence Grouping goes like this:
(false && infLoop()) || (true && true)
The compiler then looks at it, and decides it will order the execution in this order:
(true && true) THEN || THEN (false && InfLoop())

It's kindof a fact..and I don't know how else to demonstrate this. Precedence is determined by the language grammar rules. The Compiler's optimization is determined by each compiler..some are better than others, but All are free to reorder the grouped comparisons as it sees fit in order to give it the "best" chance for the fastest execution with the fewest comparisons.

Caladain
Chubsdad
cHao
Sorry, been spending too much time in an environment that specifically doesn't short circuit, thus evaluating both sides of the statement in their entirety. TRUE and FALSE were just my short hand for Evaluating the statement, resolving into the boolean result (true or false) for an expression. TRUE could equal (X>2) or the keyword "true" or whatever you want. Same with FALSE.
Caladain
Andrew
Andrew
Andrew
+1  A: 

regarding your edit: infiniteLoop() won't be evaluated because true || (whatever) is always true. Use true | (whatever) if whatever should be executed.

Philipp
Andrew
+1  A: 

about the true && true || infiniteLoop() && infiniteLoop() example, neither of the infinite loop calls are being evaluated because of the two characteristics combined: && has precedence over ||, and || short-circuits when the left side is true.

if && and || had the same precedence, the evaluation would have to go like this:

((( true && true ) || infiniteLoop ) && infiniteLoop )
(( true || infiniteLoop ) && infiniteLoop )
=> first call to infiniteLoop is short-circuited
(true && infiniteLoop) => second call to infiniteLoop would have to be evaluated

but because of &&'s precedence, the evaluation actually goes

(( true && true ) || ( infiniteLoop && infiniteLoop ))
( true || ( infiniteLoop && infiniteLoop ))
=> the entire ( infiniteLoop && infiniteLoop ) expression is short circuited
( true )
filipe
This implies left-to-right, though. In your second line:
Andrew
Andrew
Andrew