While relational (comparison) operators can be used to test whether a particular condition is true or false, they can only test one condition at a time. Often we need to know whether multiple conditions are true simultaneously. For example, to check whether we’ve won the lottery, we have to compare whether all of the multiple numbers we picked match the winning numbers. In a lottery with 6 numbers, this would involve 6 comparisons, *all* of which have to be true. In other cases, we need to know whether any one of multiple conditions is true. For example, we may decide to skip work today if we’re sick, or if we’re too tired, or if we won the lottery in our previous example. This would involve checking whether *any* of 3 comparisons is true.

Logical operators provide us with the capability to test multiple conditions.

C++ has 3 logical operators:

Operator | Symbol | Form | Operation |
---|---|---|---|

Logical NOT | ! | !x | true if x is false, or false if x is true |

Logical AND | && | x && y | true if both x and y are true, false otherwise |

Logical OR | || | x || y | true if either x or y are true, false otherwise |

**Logical NOT**

You have already run across the logical NOT unary operator in lesson 4.9 -- Boolean values. We can summarize the effects of logical NOT like so:

Logical NOT (operator !) | |
---|---|

Operand | Result |

true | false |

false | true |

If *logical NOT’s* operand evaluates to true, *logical NOT* evaluates to false. If *logical NOT’s* operand evaluates to false, *logical NOT* evaluates to true. In other words, *logical NOT* flips a Boolean value from true to false, and vice-versa.

Logical NOT is often used in conditionals:

1 2 3 4 5 |
bool tooLarge { x > 100 }; // tooLarge is true if x > 100 if (!tooLarge) // do something with x else // print an error |

One thing to be wary of is that *logical NOT* has a very high level of precedence. New programmers often make the following mistake:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> int main() { int x{ 5 }; int y{ 7 }; if (!x > y) std::cout << x << " is not greater than " << y << '\n'; else std::cout << x << " is greater than " << y << '\n'; return 0; } |

This program prints:

5 is greater than 7

But *x* is not greater than *y*, so how is this possible? The answer is that because the *logical NOT* operator has higher precedence than the greater than operator, the expression `! x > y`

actually evaluates as `(!x) > y`

. Since *x* is 5, !x evaluates to *0*, and `0 > y`

is false, so the *else* statement executes!

The correct way to write the above snippet is:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> int main() { int x{ 5 }; int y{ 7 }; if (!(x > y)) std::cout << x << " is not greater than " << y << '\n'; else std::cout << x << " is greater than " << y << '\n'; return 0; } |

This way, `x > y`

will be evaluated first, and then logical NOT will flip the Boolean result.

Best practice

If *logical NOT* is intended to operate on the result of other operators, the other operators and their operands need to be enclosed in parentheses.

Simple uses of *logical NOT*, such as `if (!value)`

do not need parentheses because precedence does not come into play.

Logical OR

The *logical OR* operator is used to test whether either of two conditions is true. If the left operand evaluates to true, or the right operand evaluates to true, or both are true, then the *logical OR* operator returns true. Otherwise it will return false.

Logical OR (operator ||) | ||
---|---|---|

Left operand | Right operand | Result |

false | false | false |

false | true | true |

true | false | true |

true | true | true |

For example, consider the following program:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> int main() { std::cout << "Enter a number: "; int value {}; std::cin >> value; if (value == 0 || value == 1) std::cout << "You picked 0 or 1\n"; else std::cout << "You did not pick 0 or 1\n"; return 0; } |

In this case, we use the logical OR operator to test whether either the left condition (value == 0) or the right condition (value == 1) is true. If either (or both) are true, the *logical OR* operator evaluates to true, which means the *if statement* executes. If neither are true, the *logical OR* operator evaluates to false, which means the *else statement* executes.

You can string together many *logical OR* statements:

1 2 |
if (value == 0 || value == 1 || value == 2 || value == 3) std::cout << "You picked 0, 1, 2, or 3\n"; |

New programmers sometimes confuse the *logical OR* operator (||) with the *bitwise OR* operator (|) (Covered later). Even though they both have *OR* in the name, they perform different functions. Mixing them up will probably lead to incorrect results.

Logical AND

The *logical AND* operator is used to test whether both operands are true. If both operands are true, *logical AND* returns true. Otherwise, it returns false.

Logical AND (operator &&) | ||
---|---|---|

Left operand | Right operand | Result |

false | false | false |

false | true | false |

true | false | false |

true | true | true |

For example, we might want to know if the value of variable *x* is between *10* and *20*. This is actually two conditions: we need to know if *x* is greater than *10*, and also whether *x* is less than *20*.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> int main() { std::cout << "Enter a number: "; int value {}; std::cin >> value; if (value > 10 && value < 20) std::cout << "Your value is between 10 and 20\n"; else std::cout << "Your value is not between 10 and 20\n"; return 0; } |

In this case, we use the *logical AND* operator to test whether the left condition (value > 10) AND the right condition (value < 20) are both true. If both are true, the *logical AND* operator evaluates to true, and the *if statement* executes. If neither are true, or only one is true, the *logical AND* operator evaluates to false, and the *else statement* executes.

As with *logical OR*, you can string together many *logical AND* statements:

1 2 3 4 |
if (value > 10 && value < 20 && value != 16) // do something else // do something else |

If all of these conditions are true, the *if statement* will execute. If any of these conditions are false, the *else statement* will execute.

Short circuit evaluation

In order for *logical AND* to return true, both operands must evaluate to true. If the first operand evaluates to false, *logical AND* knows it must return false regardless of whether the second operand evaluates to true or false. In this case, the *logical AND* operator will go ahead and return false immediately without even evaluating the second operand! This is known as short circuit evaluation, and it is done primarily for optimization purposes.

Similarly, if the first operand for *logical OR* is true, then the entire OR condition has to evaluate to true, and the second operand won’t be evaluated.

Short circuit evaluation presents another opportunity to show why operators that cause side effects should not be used in compound expressions. Consider the following snippet:

1 2 |
if (x == 1 && ++y == 2) // do something |

if *x* does not equal *1*, the whole condition must be false, so ++y never gets evaluated! Thus, *y* will only be incremented if *x* evaluates to 1, which is probably not what the programmer intended!

Warning

Short circuit evaluation may cause *Logical OR* and *Logical AND* to not evaluate one operand. Avoid using expressions with side effects in conjunction with these operators.

As with logical and bitwise OR, new programmers sometimes confuse the *logical AND* operator (&&) with the *bitwise AND* operator (&).

Mixing ANDs and ORs

Mixing *logical AND* and *logical OR* operators in the same expression often can not be avoided, but it is an area full of potential dangers.

Many programmers assume that *logical AND* and *logical OR* have the same precedence (or forget that they don’t), just like addition/subtraction and multiplication/division do. However, *logical AND* has higher precedence than *logical OR*, thus *logical AND* operators will be evaluated ahead of *logical OR* operators (unless they have been parenthesized).

New programmers will often write expressions such as `value1 || value2 && value3`

. Because *logical AND* has higher precedence, this evaluates as `value1 || (value2 && value3)`

, not `(value1 || value2) && value3`

. Hopefully that’s what the programmer wanted! If the programmer was assuming left to right evaluation (as happens with addition/subtraction, or multiplication/division), the programmer will get a result he or she was not expecting!

When mixing *logical AND* and *logical OR* in the same expression, it is a good idea to explicitly parenthesize each operator and its operands. This helps prevent precedence mistakes, makes your code easier to read, and clearly defines how you intended the expression to evaluate. For example, rather than writing `value1 && value2 || value3 && value4`

, it is better to write `(value1 && value2) || (value3 && value4)`

.

Best practice

When mixing *logical AND* and *logical OR* in a single expression, explicitly parenthesize each operation to ensure they evaluate how you intend.

De Morgan’s law

Many programmers also make the mistake of thinking that `!(x && y)`

is the same thing as `!x && !y`

. Unfortunately, you can not “distribute” the *logical NOT* in that manner.

De Morgan’s law tells us how the *logical NOT* should be distributed in these cases:

`!(x && y)`

is equivalent to `!x || !y`

`!(x || y)`

is equivalent to `!x && !y`

In other words, when you distribute the *logical NOT*, you also need to flip *logical AND* to *logical OR*, and vice-versa!

This can sometimes be useful when trying to make complex expressions easier to read.

Where’s the logical exclusive or (XOR) operator?

*Logical XOR* is a logical operator provided in some languages that is used to test whether an odd number of conditions is true.

Logical XOR | ||
---|---|---|

Left operand | Right operand | Result |

false | false | false |

false | true | true |

true | false | true |

true | true | false |

C++ doesn’t provide a *logical XOR* operator. Unlike *logical OR* or *logical AND*, *logical XOR* cannot be short circuit evaluated. Because of this, making a *logical XOR* operator out of *logical OR* and *logical AND* operators is challenging. However, you can easily mimic *logical XOR* using the *inequality* operator (!=):

1 |
if (a != b) ... // a XOR b, assuming a and b are Booleans |

This can be extended to multiple operands as follows:

1 |
if (a != b != c != d) ... // a XOR b XOR c XOR d, assuming a, b, c, and d are Booleans |

Note that the above XOR patterns only work if the operands are Booleans (not integers). If you need a form of *logical XOR* that works with non-Boolean operands, you can static_cast them to bool:

1 |
if (static_cast<bool>(a) != static_cast<bool>(b) != static_cast<bool>(c) != static_cast<bool>(d)) ... // a XOR b XOR c XOR d, for any type that can be converted to bool |

Quiz time

Question #1

Evaluate the following expressions.

Note: in the following answers, we “explain our work” by showing you the steps taken to get to the final answer. The steps are separated by a *=>* symbol. Expressions that were ignored due to the short circuit rules are placed in square brackets. For example

(1 < 2 || 3 != 3) =>

(true || [3 != 3]) =>

(true) =>

true

means we evaluated (1 < 2 || 3 != 3) to arrive at (true || [3 != 3]) and evaluated that to arrive at “true”. The 3 != 3 was never executed due to short circuiting.

a) (true && true) || false

b) (false && true) || true

c) (false && true) || false || true

d) (5 > 6 || 4 > 3) && (7 > 8)

e) !(7 > 6 || 3 > 4)

5.x -- Chapter 5 summary and quiz |

Index |

5.6 -- Relational operators and floating point comparisons |

Is the order of evaluation of operations to operators also not defined? I come from a Java background, so I always try to put the least-intensive or most likely conditions first in a logical operand. So, I'll do

if condition1 is less expensive than condition2. Are operands done left-to-right? Or is it undefined and irrelevant?

The order of evaluation of operands for operators is well defined, and covered in https://www.learncpp.com/cpp-tutorial/operator-precedence-and-associativity/

The order of evaluation for other parts of expressions, and for function arguments, is not well defined. https://en.cppreference.com/w/cpp/language/eval_order

Hi Guys,

Just wondering the logic behind:

bool tooLarge { x > 100 };

Is tooLarge a variable? How can you assign a x > 100 to a binary variable?

Doh, I figured it out. It's just a ?statement? that gets evaluated and then stored as either true or false.

x > 100 evaluates to a bool and variable tooLarge is initialized with this value

need more explanation for De Morgan's Law please..

given : Many programmers also make the mistake of thinking that !(x && y) is the same thing as !x && !y

could you please replace x and y with actual values and put a sample conditional statement

so we can get a better picture of why !(x && y) is not the same as !x && !y

because often in my previous language (Visual Foxpro) i use something like :

if !( 1==1 and 2==2) ( requires both of them to be NOT TRUE in order to return TRUE )

which also translates to

if ! 1==1 and ! 2==2

and so i was wondering why !( 1==1 and 2==2) should be ! 1==1 or ! 2==2 ( requires only one of them to be NOT TRUE in order to return TRUE )

it would be much appreciated thank you.

Well there are only four possibilities, so we can just work through all of them. For readability I didn't show my working.

(x, y) = (false, false) => !(x && y) = true

De Morgan's law: true

Mistaken identity: true

(x, y) = ( true, false) => !(x && y) = true

De Morgan's law: true

Mistaken identity: false

(x, y) = (false, true) => !(x && y) = true

De Morgan's law: true

Mistaken identity: false

(x, y) = ( true, true) => !(x && y) = false

De Morgan's law: false

Mistaken identity: false

So in two of the cases the mistaken identity just so happens to give the correct answer, but it is in general not equivalent.

Maybe your confusion is coming from this, as well as the sentences about 'requiring only one of them to be NOT TRUE'? Since you're using 1==1 and 2==2; these two expressions are always equal to 'true' since they don't have any variables?

First "Best practice" block and the next line: "parenthesis" should be "parentheses".

After the XOR table:

> Because of this, making an logical XOR operator

"an" should be "a".

I was wondering throughout the whole lesson whether c++ has an XOR operator. I was really surprised when I saw that `!=` does the same job xD

I learned a lot of things in this tutorial, thanks a lot Alex and nascardriver!

There should be a correction in this code snippet:

"x is not greater than y" will be printed when the if condition !(x > y) evaluates to true which is when x > y will evaluate to false. That will happen when either x equals y or when x is less than y. In other words that will happen when x is not greater than y. Which matches this case's corresponding std::cout text "x is not greater than y" so this case is fine.

WHEREAS, in the second case, "x is equal to or greater than y" will get printed when the if condition !(x > y) evaluates to false which is when x > y will evaluate to true. That will happen only when x is greater than y. But this doesn't match it's corresponding std::cout text "x is equal to or greater than y". Rather the std::cout text should be "x is greater than y".

I know it doesn't matter what the output text in either if or else says as this example is there to magnify the precedence of the logical ! operator, but if anybody took those texts literally and got confused like me, hope this clarifies your doubt!

Good catch, message updated!

thanks for the great tutorials

i have the following code :

int age {20};

int height{30};

if(age && height)

std::cout << "welcome to our website";

else

std::cout << "please enter your age and hieght";

what happen to age and height in the condtion are they evaluate to 20 and 30 or both evaluate to 1 ?

Hi!

First of all thank you for this great book. I'm learning a lot through it.

I would like to suggest a modification in the precedence example of the logical NOT.

this is what we have:

```

#include <iostream>

int main()

{

int x { 5 };

int y { 7 };

if (! x > y)

std::cout << "x is not greater than y\n";

else

std::cout << "x is equal to or greater than y\n";

return 0;

}

```

Well, 5 is smaller than 7 and changing it to 0 with the `!` won't change the result.

If the values of x and y where like this:

```

int x { 7 };

int y { 5 };

```

The argument would be clearer.

PS: why code formatting isn't working?

Hey dear Alex!

Thanks for the great tutorials!

Just one thing on Short circuit evaluation section:

Similarly, if the first operand for logical OR is true, then the entire OR condition has to evaluate to true, and the second operand won’t be be evaluated.

Shouldn't be:

Similarly, if the first operand for logical OR is true, then the entire OR condition has to evaluate to true, and the second operand won’t be evaluated.

In this example you provided, we see Short Circuit Evaluation in action. I'm curious about how it happens: does the processor specifically keep in "mind" that it is evaluating an and or an or expression and therefore perform additional checks in between evaluating single expressions?

E.g. ((expr1) && (expr2)); Oh, this expression contains an AND, schedule a check on the value of expr1 after we have evaluated it and before evaluating expr2.

Whereas if we have, for example, a sum operator ((expr1) + (expr2)); Oh, no AND or OR here, evaluate expr1 -> (no check on expr1 here) -> evaluate expr2 -> evaluate the full expr

I'll use goto to show how this works. Starting with

Turning this into again C++, but the structure is closer to what the CPU sees

No additional comparisons are needed.

If you're willing to learn a bit of assembly, you can check this out yourself in compiler explorer https://godbolt.org/z/7Kv679 (Bottom right is what the CPU sees (Converted to a human-readable format)).

Can you complete this code -!x && !y- and explain how it works? I tried and couldn’t get it work.

What is a bitwise OR operator ?

Answer:

AND OR XOR bitwise are thought in lessen 0.2

Why did you not answer this question? You did not mention anything about bitwise till this lessen, so how on earth should I know????

I added a comment to the lesson saying that the bitwise operators are covered later. There's no need to know what they do to understand this lesson, you just need to know that they exist.

I didn't reply to your first comment, because there was a big pile of comments I had to work through. When I don't have enough time to look at all of them, I have to skip some without ever reading them. That's unfortunate, but there's nothing I can do about it.

How does ! Evaluate x (5) to 0?

! Flips the opposite, 0 is not the opposite of 5, is it because none is the opposite of some? What happens if x is 0 and ! X to what does it evaluate? Only to 1? Is only 1 the opposite of none? Is the compiler programmed the flip should be minimum?

in boolean anything greater than zero is true, so x is true and if you flip it, it becomes false or 0.

Wrong. We’re dealing here with "not" operator not Boolean. ! flips the value, it’s not about true or false.

Ethan is right. When you apply the ! to an integer, the integer is converted to a boolean. 0 is false, everything else is true. `!x` is true if `x` is 0.

I have two questions:

1) Can we string together many relational statements?

2) When I ran your code, I got the following warning, what does it mean?

"unsafe use of type 'bool' in operation"

1) If you mean

Then no, you have to do one comparison after the other

2) `!x` is a `bool`. Comparing a `bool` with `>` doesn't make sense, so your compiler warns you.

Thank you so much nascadriver.

Just a quick question, in this code:

When I input 0, the if sentence runs, but if I input 1, it doesn't.

When I input 0 the bool values are a=0, b=1, c=0.

When I input 1 the bool values are a=1, b=0, c=1.

Why does the if sentence not work when I input 1?

Wait I think I understand why.

When I input 0, a is false, b is true and c is false.

Since it compares first a!=b, this will come out as true and than it compares

the result, meaning (a!=b)!=c, since (a!=b) is true and c is false, this works out.

But when 1 is input, c is true, meaning when (a!=b)!=c, it's actually true!=true so it doesn't run the if part.

Might be helpful to mention that it works this way, or some like me might get lost for a second, since I thought it just compares one with the next and not the result of 2 and with the next.

Hello!

I misunderstood the next example with the short circuit demo

As to the table of the precedence the ++ operator has higher precedence than the logical && so

why is the logical && is evaluated first?

Is not this to be correct one though?

Though after running the snippet with int X = 3, int Y = 4 the logical operator && evaluates first anyway and Y remains 4.Why?

&& is executed left-to-right. This is unrelated to operator precedence.

If `x` was 1

Thanks nascardriver, I think more likely it relates somehow to the order of evaluation so should revisit it

Write the code and analyze them-

If a = 2, b = 4, and c = 6, indicate whether each of the following conditions is true or false:

A) (a == 4) || (b > 2)

B) (6 <= c) && (a > 3) w

C) (1 != b) && (c != 3)

D) (a >= -1) || (a <= b)

E) !(a > 2)

can anyone solve it?

Please help me, I'm desperate: why does the first one (with &&) works and not the second one (with ||)?

It should be while(everything there is true) do this, otherwise keep executing the program right?

So from a logical point of view those examples are strange af:

If we use (choice != 1 && choice != 2 && choice != 3), we're saying that everything MUST be TRUE (so that the choice must be 1,2 and 3 at the same time), but this works!

From a logical point of view it should be (choice != 1 || choice != 2 || choice != 3) so when we type one of the three numbers the while becomes instantly false and so we get out of the while. BUT THIS DOESN'T WORK, WHYYYYYYYYYYYYYYYY? I'm screaming lmao.

The loop runs as long as the condition is true.

Everything must be true in order for the loop to keep running.

If at least 1 of your conditions is false, the loop stops.

With `||`, you get an infinite loop, because all conditions would have to be false at the same time.