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.
| Operator | Meaning | Example |
|---|---|---|
| + | Addition | 3 + 4 → 7 |
| - | Subtraction | 9 - 3 → 6 |
| * | Multiplication | 4 * 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.
| Operator | Meaning | Example (int a=3, b=5) |
|---|---|---|
| == | Equal to | a == 3 → true, a == b → false |
| != | Not equal to | a != b → true |
| < | Less than | a < b → true |
| > | Greater than | a > b → false |
| <= | Less than or equal | a <= 3 → true |
| >= | Greater than or equal | b >= 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().
| Operator | Meaning | True when |
|---|---|---|
| && | Logical AND | Both sides are true |
| || | Logical OR | At least one side is true |
| ! | Logical NOT | The 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 parenthesesKey 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++.