Skip to content
C++

Arithmetic, Comparison, and Logical Operators

Operators are the symbols that tell C++ how to compute values from existing values. You already know most of them from mathematics — addition, subtraction, multiplication — but C++ adds several that are specific to programming: modulo for remainders, increment and decrement shortcuts, bitwise operations for working with individual bits, and compound assignment operators that modify a variable in one step. Understanding how operators combine and their relative precedence (which operations happen first) prevents subtle bugs in expressions.

Arithmetic operators

The basic five arithmetic operators work on both integer and floating-point types. Integer division is the key trap: when both operands are integers, division produces an integer result by truncating toward zero. Modulo gives the remainder after integer division — it is only defined for integers.

OperatorMeaningExample
+Addition3 + 4 → 7
-Subtraction9 - 3 → 6
*Multiplication4 * 5 → 20
/Division (truncates for int)7 / 2 → 3, 7.0 / 2 → 3.5
%Modulo (remainder)7 % 3 → 1, -7 % 3 → -1
int a = 17, b = 5;

int q = a / b;    // 3  — quotient (truncated)
int r = a % b;    // 2  — remainder

// Verify: a == b * q + r  →  17 == 5*3 + 2  ✓

// Common use of %: test if a number is even or odd
if (n % 2 == 0) { /* even */ }
if (n % 2 != 0) { /* odd  */ }

// Convert an integer index into a circular range [0, size):
int wrapped = index % size;

Increment and decrement

The ++ and -- operators add or subtract 1 from a variable. They come in two forms: prefix (before the variable) and postfix (after the variable). Both modify the variable, but they differ in what value they produce when used as part of a larger expression. In practice, if you are using the operator for its side effect only (not its value), the two forms are equivalent — prefix is slightly preferred in C++ because it avoids creating a temporary copy.

int i = 5;

// Prefix — increments first, then produces the NEW value
int a = ++i;   // i becomes 6, a = 6

i = 5;
// Postfix — produces the OLD value, then increments
int b = i++;   // a = 5 (old value), then i becomes 6

// As standalone statements, both are identical:
i++;    // same as ++i when the result value is not used
++i;    // prefer prefix by convention

Compound assignment operators

Compound assignment operators combine an arithmetic operation and assignment into one step. x += 5 is exactly equivalent to x = x + 5 but shorter and often clearer.

int score = 100;

score += 10;   // score = 110
score -= 5;    // score = 105
score *= 2;    // score = 210
score /= 3;    // score = 70 (integer division: 210/3)
score %= 4;    // score = 2 (70 % 4)

Comparison operators

Comparison operators compare two values and produce a bool result. They are used in conditions for if statements and loops. The most common mistake is using = (assignment) instead of == (equality comparison) — this is syntactically valid but logically wrong, and -Wall will warn about it.

OperatorMeaningExample (int a=3, b=5)
==Equal toa == 3 → true, a == b → false
!=Not equal toa != b → true
<Less thana < b → true
>Greater thana > b → false
<=Less than or equala <= 3 → true
>=Greater than or equalb >= 5 → true
int age = 18;

if (age >= 18) {
    std::cout << "Adult\n";
}

// Bug: assignment instead of comparison
if (age = 21) {   // ALWAYS true — assigns 21 to age, then tests 21
    std::cout << "Bug!\n";
}

// Fix: use ==
if (age == 21) { ... }

Logical operators

Logical operators combine or negate boolean expressions. The AND operator (&&) and OR operator (||) use short-circuit evaluation: the right-hand side is only evaluated if the result is not already determined by the left-hand side. For &&, if the left side is false, the whole expression is false regardless of the right side — so the right is skipped. For ||, if the left side is true, the whole expression is true — right side skipped. This makes it safe to write guards like p != nullptr && p->isValid().

OperatorMeaningTrue when
&&Logical ANDBoth sides are true
||Logical ORAt least one side is true
!Logical NOTThe operand is false
int x = 7;
bool inRange = (x >= 0 && x < 10);  // true — AND
bool valid   = (x == 0 || x > 5);   // true — OR
bool notZero = !(x == 0);           // true — NOT

// Short-circuit prevents the null dereference:
std::string* p = nullptr;
if (p != nullptr && p->empty()) {  // p->empty() is NEVER called if p is null
    std::cout << "empty";
}

Operator precedence

When multiple operators appear in one expression, C++ evaluates them in a fixed priority order called precedence. Multiplication binds more tightly than addition (just like in math), so 2 + 3 * 4 is 14, not 20. Comparison operators bind more tightly than logical operators, so a > 0 && b < 10 is parsed as (a > 0) && (b < 10).

You do not need to memorize the full precedence table. The practical rule is: when in doubt, add parentheses. Parentheses are free and make intent explicit.

// Precedence examples:
int a = 2 + 3 * 4;    // 14  — * before +
int b = (2 + 3) * 4;  // 20  — parentheses override

bool c = 5 > 3 && 2 < 4;      // true — comparisons first, then &&
bool d = 5 > 3 && 2 < 4 || 0; // true — && before ||

// Common mistake: forgetting precedence with bitwise and comparison
// if (a & 0xFF == 0)    — parsed as a & (0xFF == 0) — wrong!
if ((a & 0xFF) == 0) { }   // correct — add parentheses

Key rules to remember

Integer division truncates — use a double literal or cast to get a fractional result

7 / 2 is 3. Write 7.0 / 2 or (double)7 / 2 to get 3.5.

== is comparison; = is assignment — never confuse them in a condition

if (x = 5) assigns 5 to x and always evaluates as true (since 5 is non-zero). Use if (x == 5) to test equality.

&& and || short-circuit — the right side may not be evaluated

Use this to guard against null pointer dereferences: if (p && p->valid()). The p->valid() call is only made if p is non-null.

When in doubt about precedence, add parentheses

Explicit parentheses prevent misreading and make intent clear. They have zero runtime cost.

% is modulo, not percentage — it gives the remainder after integer division

n % 2 == 0 tests for even numbers. The result has the same sign as the left operand in C++.

Sign in to track progress