CppRelational & Logical Operators

Relational & Logical Operators

Relational operators compare two values and produce a bool (true/false). Logical operators combine or invert boolean expressions. Together they form the backbone of every conditional and loop in C++.
Relational Operators

Operator

Meaning

Example

==

Equal to

a == b

!=

Not equal to

a != b

Greater than

a > b

<

Less than

a < b

=

Greater than or equal to

a >= b

<=

Less than or equal to

a <= b

Logical Operators

Operator

Meaning

Example

&&

Logical AND — true only if both sides are true

isValid && isReady

||

Logical OR — true if at least one side is true

isAdmin || isOwner

!

Logical NOT — inverts a boolean

!isExpired

Short-Circuit Evaluation
&& and || do not always evaluate their right-hand side. If the left side of && is false, the overall result must be false regardless of the right side, so the right side is skipped entirely. The same applies to || when the left side is true. This is not just an optimization — code routinely relies on it for safety.

CPP
#include <iostream>

bool isSafeToDivide(int numerator, int denominator) {
    // If denominator == 0, the left side is false, so the division on the
    // right is NEVER evaluated — this pattern safely guards against
    // division by zero.
    return denominator != 0 && (numerator / denominator) > 1;
}

int main() {
    std::cout << isSafeToDivide(10, 0) << std::endl; // false, no crash
    return 0;
}
Never Compare Floating-Point Numbers with ==
Floating-point precision makes == unreliable
Floating-point values (float, double) cannot exactly represent most decimal fractions in binary. Two computations that are mathematically equal can end up with tiny representation differences, so == often returns false when you expect true. Instead, compare whether the values are within a small tolerance (epsilon) of each other.

CPP
#include <cmath>
#include <iostream>

int main() {
    double a = 0.1 + 0.2;
    double b = 0.3;

    std::cout << (a == b) << std::endl; // false! (0.30000000000000004 != 0.3)

    // Correct approach: compare within a small epsilon
    const double epsilon = 1e-9;
    bool almostEqual = std::fabs(a - b) < epsilon;
    std::cout << almostEqual << std::endl; // true
    return 0;
}
Comparing Different Numeric Types

Comparing a signed and an unsigned integer can silently produce the wrong answer because the compiler converts the signed value to unsigned before comparing — a negative number becomes a very large positive one. This is covered in depth on the Type Modifiers page; the short version:

CPP
int signedValue = -1;
unsigned int unsignedValue = 1;

// signedValue is converted to unsigned, becoming a huge number:
std::cout << (signedValue < unsignedValue) << std::endl; // false — surprising!
Note
Most compilers will warn about signed/unsigned comparisons (-Wsign-compare in GCC/Clang). Treat that warning seriously rather than suppressing it.
  • Use ==/!= freely for integers, characters, booleans, and pointers

  • Never use ==/!= directly on float/double — use an epsilon comparison

  • Match signedness before comparing mixed integer types, or cast explicitly