Operators & Expressions

Operators combine with operands to build expressions, and nearly every line of C++ code you write leans on them — from simple arithmetic to conditional logic and bit manipulation.

Operators and expressions are fundamental parts of C++. An operator performs an operation, while an expression combines values, variables, functions, and operators to produce a result. Understanding how operators and operands come together to form expressions — and what value and type each expression produces — is the foundation for reading and writing almost any C++ statement.

What Is an Operator?

Here + is an operator; a and b are operands; a + b is an expression; result receives the value produced by the expression.

An operator is a symbol or keyword that tells C++ to perform a particular operation. Examples include a + b, a - b, a * b, a / b, a == b, and a && b.

A quick reference list of common C++ operators, loosely grouped by family.

The meaning and behavior of an operator depend on its operands and their types.

int a = 10;
int b = 5;
int result = a + b;
+   -   *   /   %
==  !=  <   >   <=  >=
&&  ||  !
=   +=  -=  *=  /=
++  --
&   |   ^   ~
<<  >>

What Is an Expression?

An expression is a combination of operands and operators that can be evaluated according to C++ rules. Examples include 10 + 20, x * 5, a > b, and x = 100.

The expression 10 + 20 produces the value 30, which is then stored in result.

int result = 10 + 20;

Operands

The values or objects that an operator acts on are called operands. In a + b, a is an operand, + is the operator, and b is the second operand.

Another example: -x — here - is a unary operator and x is its single operand.

Operators Based on Number of Operands

Operators can be classified by how many operands they operate on.

A unary operator works with one operand, such as -x, ++x, or !flag. A binary operator works with two operands, such as a + b, a * b, or a == b. A ternary operator works with three operands, such as condition ? value1 : value2. The conditional operator ?: is C++'s primary ternary operator.

Arithmetic Operators

Arithmetic operators perform mathematical operations.

Prints 13, 7, 30, 3, and 1 in order.

a / b -> 3 (integer division) a % b -> 1 (remainder) Because a and b are integers, 10 / 3 performs integer division.

Operator   Meaning
--------   --------------
+          Addition
-          Subtraction
*          Multiplication
/          Division
%          Remainder
int a = 10;
int b = 3;
std::cout << a + b << '\n';
std::cout << a - b << '\n';
std::cout << a * b << '\n';
std::cout << a / b << '\n';
std::cout << a % b << '\n';

Addition +

The + operator performs addition for arithmetic operands. Result: 30.

+ also works with floating-point values. Result: 4.0.

C++ also overloads + for certain library types, such as strings.

int a = 10;
int b = 20;
int result = a + b;
double x = 2.5;
double y = 1.5;
double result = x + y;

Subtraction -

The same symbol is also used as the unary minus operator. Here -x means "the negative of x."

int a = 20;
int b = 8;
int result = a - b;
int x = 10;
int y = -x;

Multiplication *

The * symbol has other meanings in C++, including pointer-related operations, which are covered separately.

int a = 6;
int b = 7;
int result = a * b;

Division /

With floating-point operands, the result is approximately 3.333333...

Integer division produces 3. The fractional part is discarded because the operation is performed using integer arithmetic.

int a = 10;
int b = 2;
int result = a / b;
double result = 10.0 / 3.0;
int result = 10 / 3;

Remainder Operator %

The % operator produces the remainder of integer division.

It is commonly used for checking divisibility, detecting even/odd values, and repeating patterns.

Tests whether number is even by checking if the remainder after dividing by 2 is zero.

The % operator is for integral operands.

int result = 10 % 3;
int result = 17 % 5;
if (number % 2 == 0)
{
    std::cout << "Even";
}

Relational Operators

Relational operators compare values.

These operators produce a Boolean result.

Operator   Meaning
--------   ----------------------
<          Less than
>          Greater than
<=         Less than or equal
>=         Greater than or equal
int a = 10;
int b = 20;
bool result = a < b;

Equality Operators

C++ provides == (equal to) and != (not equal to).

Output: Equal.

The not-equal operator runs its branch when the two operands differ.

int a = 10;
int b = 10;
if (a == b)
{
    std::cout << "Equal";
}
if (a != b)
{
    // Values are different
}

= vs ==

Assignment: x = 10; — this assigns 10 to x. Equality comparison: x == 10; — this checks whether x equals 10.

The condition compares x against 10 without modifying x.

Writing if (x = 10) instead of if (x == 10) compiles but assigns 10 to x and then tests the assigned (truthy) value, so the branch always runs — only intentional when assignment inside the condition is genuinely wanted.

if (x == 10)
{
    // ...
}

Logical Operators

Logical operators combine or invert Boolean conditions.

Operator   Meaning
--------   -------------
&&         Logical AND
||         Logical OR
!          Logical NOT

Logical AND &&

&& is true when both operands are true.

bool a = true;
bool b = true;
bool result = a && b;
A       B       A && B
-----   -----   ------
false   false   false
false   true    false
true    false   false
true    true    true

Logical OR ||

|| is true when at least one operand is true.

bool a = true;
bool b = false;
bool result = a || b;
A       B       A || B
-----   -----   ------
false   false   false
false   true    true
true    false   true
true    true    true

Logical NOT !

! reverses a Boolean value.

Result: false.

Runs the branch when isReady is false.

bool value = true;
bool result = !value;
if (!isReady)
{
    std::cout << "Not ready";
}

Short-Circuit Evaluation

C++'s logical operators && and || use short-circuit evaluation. For A && B, if A is false, B does not need to be evaluated. For A || B, if A is true, B does not need to be evaluated.

The second condition is evaluated only if ptr != nullptr is true. This behavior is important because the second operand may depend on the first condition.

if (ptr != nullptr && *ptr == 10)
{
    // ...
}

Assignment Operators

The basic assignment operator is =.

Assigns 100 to x.

C++ also provides compound assignment operators.

Equivalent to x = x + 5. Result: 15.

int x;
x = 100;
Operator   Equivalent idea
--------   --------------------
+=         Add and assign
-=         Subtract and assign
*=         Multiply and assign
/=         Divide and assign
%=         Remainder and assign
int x = 10;
x += 5;

Compound Assignment

Each compound assignment updates x in place, chaining from its previous value.

x -= 5 -> x becomes 15 x *= 2 -> x becomes 30 x /= 3 -> x becomes 10 x %= 4 -> x becomes 2

Compound assignment can make repeated updates concise.

int x = 20;
x -= 5;   // 15
x *= 2;   // 30
x /= 3;   // 10
x %= 4;   // 2

Increment Operator ++

The increment operator increases a value by one.

There are two forms: ++x; (prefix) and x++; (postfix).

int x = 10;
++x;

Prefix Increment

The increment happens before the value is used. Conceptually: x becomes 11, and result receives 11.

int x = 10;
int result = ++x;

Postfix Increment

The original value is used first, then x is incremented. Conceptually: result receives 10, and x becomes 11.

int x = 10;
int result = x++;

Decrement Operator --

The decrement operator decreases a value by one.

Like increment, it has prefix and postfix forms: --x; and x--; The same prefix/postfix distinction applies.

int x = 10;
--x;

Prefix vs Postfix

x++ prints the current value of x (5), then increments x to 6

The second line prints the now-updated x (6)

Expression   Meaning
----------   -----------------------
++x          Increment, then use
x++          Use, then increment
--x          Decrement, then use
x--          Use, then decrement
int x = 5;
std::cout << x++ << '\n';
std::cout << x << '\n';

Bitwise Operators

C++ provides operators that work at the level of individual bits of integral values.

Applies bitwise AND to the individual bits of a and b.

The bitwise operators are different from the logical operators &&, ||, and !.

Operator   Meaning
--------   ------------
&          Bitwise AND
|          Bitwise OR
^          Bitwise XOR
~          Bitwise NOT
<<         Left shift
>>         Right shift
unsigned int a = 0b1010;
unsigned int b = 0b1100;
unsigned int result = a & b;

Bitwise AND &

For each bit: 1 & 1 -> 1, 1 & 0 -> 0, 0 & 1 -> 0, 0 & 0 -> 0.

Bitwise AND is commonly used for masking and testing bits.

1010
1100
----
1000

Bitwise OR |

For each bit: 1 | 1 -> 1, 1 | 0 -> 1, 0 | 1 -> 1, 0 | 0 -> 0.

1010
1100
----
1110

Bitwise XOR ^

XOR produces 1 when the two bits are different: 1 ^ 1 -> 0, 1 ^ 0 -> 1, 0 ^ 1 -> 1, 0 ^ 0 -> 0.

1010
1100
----
0110

Bitwise NOT ~

~ inverts the bits of its operand.

The exact resulting value depends on the width and type of x.

Bitwise NOT should therefore be understood in terms of the complete representation of the operand's type.

unsigned int x = 0b1010;
auto result = ~x;

Shift Operators

Left shift: x << n. Right shift: x >> n.

Conceptually, 0100 shifted left becomes 1000. The result is 8 in this example.

Shift counts must be within the valid range for the promoted left operand; invalid shift counts result in undefined behavior.

unsigned int x = 4;
unsigned int result = x << 1;

Important Difference: Logical vs Bitwise

These operators look similar but have different purposes. Logical: && || !. Bitwise: & | ^ ~.

Logical AND operates on logical conditions.

Bitwise AND operates on the individual bits of integral operands.

Logical operators operate on logical conditions. Bitwise operators operate on the bits of integral operands.

bool result = true && false;
int result = 0b1010 & 0b1100;

Conditional Operator ?:

The conditional operator is a ternary operator. Syntax: condition ? expression1 : expression2.

If the condition is true, expression1 is selected. Otherwise, expression2 is selected.

It is useful for concise conditional expressions.

int age = 20;
int result = age >= 18 ? 1 : 0;
condition
            |
        +---+---+
      true      false
        |           |
     expr1       expr2
         \         /
          \       /
           result

Assignment Is Also an Expression

In C++, assignment produces a value.

This works because x = 10 produces the assigned value, which is then used by y = ... After execution: x = 10, y = 10.

Although valid, deeply chained assignments can reduce readability.

int x;
int y;
y = x = 10;

Comma Operator

The comma operator evaluates its left operand, then its right operand.

The result of the expression is 2.

The comma operator is different from commas used merely as separators in declarations, function arguments, initializer lists, and other syntax.

It is most commonly encountered in for loops, where the comma sequences multiple init or update expressions.

int x = (1, 2);
for (int i = 0, j = 10; i < j; ++i, --j)
{
}

sizeof Operator

sizeof determines the size of a type or object in bytes.

Gets the size, in bytes, of the object x.

sizeof can also be applied directly to a type.

Prints the size of int on the current implementation.

The exact size is implementation-dependent. sizeof is an operator, not a function.

int x;
std::size_t size = sizeof(x);
std::size_t size = sizeof(int);
std::cout << sizeof(int) << '\n';

typeid Operator

C++ provides the typeid operator for obtaining type information.

Prints an implementation-defined string describing the type of x.

The exact string returned by name() is implementation-dependent. typeid is particularly relevant when working with runtime type information.

#include <typeinfo>

int x = 10;
std::cout << typeid(x).name();

Scope Resolution Operator ::

The scope resolution operator :: is used to qualify names with a scope. For example, std::cout means cout is being accessed from the std namespace.

It is also used with class members and other scopes: ClassName::member. Its detailed uses are covered in the relevant namespace and class topics.

Member Access Operators

C++ provides . and -> for accessing members. For an object: object.member. For a pointer to an object: pointer->member.

These operators are important parts of C++ syntax, though detailed pointer and class behavior belongs to their respective topics.

Operator Precedence

When an expression contains multiple operators, C++ uses operator precedence to determine grouping.

Multiplication has higher precedence than addition. Therefore: 2 + (3 * 4). Result: 14, not (2 + 3) * 4.

Precedence and associativity are covered in greater detail in the separate Operator Precedence & Associativity topic.

int result = 2 + 3 * 4;

Parentheses

Parentheses can explicitly control grouping.

Equivalent in meaning to a + b * c, since multiplication already has higher precedence, but the parentheses make the grouping explicit.

This expression has a different meaning: a and b are added first, and the sum is then multiplied by c.

When an expression could be difficult to read, parentheses can make the intended evaluation clearer.

int result = a + (b * c);
int result = (a + b) * c;

Expression Categories by Purpose

Expressions commonly appear in different roles: an arithmetic expression such as a + b * c, a relational expression such as a > b, a logical expression such as a > 0 && b > 0, an assignment expression such as x = 100, and a conditional expression such as x > 0 ? x : -x.

Expressions can also be nested, combining smaller expressions into a larger one.

int result = (a + b) * (c - d);

Side Effects

Some expressions do more than simply produce a value. For example, x++; produces a value but also modifies x. Similarly, x = 10; changes the stored value of x. This modification is called a side effect.

Be careful when multiple modifications and reads of the same object appear in a complicated expression. Prefer simple, readable expressions over clever ones.

Expression Statements

An expression can be used as a statement by placing a semicolon after it.

This is syntactically an expression statement, although the computed value is discarded.

More useful examples: each is an expression followed by a semicolon.

x = 10;
x++;
function();

Type of an Expression

Expressions have types.

The expression a + b has an integer type, so result is deduced accordingly.

The expression produces a floating-point result, since one operand is a double.

Understanding expression types is important because C++ uses them to determine conversions and which operations are valid.

int a = 10;
int b = 20;
auto result = a + b;
double a = 10.0;
int b = 2;
auto result = a / b;

Best Practices

1. Prefer readable expressions. Instead of unnecessarily complex expressions like result = a++ + ++b;, prefer separate operations when clarity matters.

2. Use parentheses when they improve clarity: result = (a + b) * c;

3. Understand operand types. Before evaluating an expression, consider: what are the operand types? what conversions occur? what type is the result?

4. Use the correct operator family: && is logical AND, & is bitwise AND.

5. Be careful with division. Know whether your operands are integral or floating-point.

6. Avoid unnecessary cleverness. Readable expressions are generally easier to debug, maintain, and review.

Quick Reference

Arithmetic:           a + b, a - b, a * b, a / b, a % b
Comparison:           a == b, a != b, a < b, a > b, a <= b, a >= b
Logical:              a && b, a || b, !a
Assignment:           x = value;, x += value;, x -= value;, x *= value;, x /= value;, x %= value;
Increment/decrement:  ++x;, x++;, --x;, x--;
Bitwise:              a & b, a | b, a ^ b, ~a, a << n, a >> n
Conditional:          condition ? value1 : value2
Other important ops:  sizeof(value), sizeof(Type), typeid(value), a, b, scope::name, object.member, pointer->member

Operator Categories at a Glance

C++ Operators
|
+-- Arithmetic
|   +-- +
|   +-- -
|   +-- *
|   +-- /
|   `-- %
|
+-- Comparison
|   +-- ==
|   +-- !=
|   +-- <
|   +-- >
|   +-- <=
|   `-- >=
|
+-- Logical
|   +-- &&
|   +-- ||
|   `-- !
|
+-- Assignment
|   +-- =
|   +-- +=
|   +-- -=
|   +-- *=
|   +-- /=
|   `-- %=
|
+-- Increment / Decrement
|   +-- ++
|   `-- --
|
+-- Bitwise
|   +-- &
|   +-- |
|   +-- ^
|   +-- ~
|   +-- <<
|   `-- >>
|
+-- Conditional
|   `-- ?:
|
`-- Other
    +-- sizeof
    +-- typeid
    +-- ,
    +-- ::
    +-- .
    `-- ->

Mental Model

Think of an expression as a calculation or operation that produces a result.

Conceptually: a + b becomes an intermediate result, which is then used as result * c to produce the final value.

The exact evaluation behavior depends on the operators, operand types, conversions, precedence, associativity, and sequencing rules.

What is the difference between the = operator and the == operator, and what does each one do to its left-hand operand?

= is the assignment operator: it stores the value of its right operand into its left operand and the expression's value is that stored value. == is the equality operator: it compares the two operands and produces a bool (true or false) without modifying either operand. x = 10 changes x; x == 10 only tests whether x currently equals 10.

Given int a = 10, b = 3;, explain why a / b evaluates to 3 while static_cast<double>(a) / b or 10.0 / 3.0 evaluates to approximately 3.333.

When both operands of / are integer types, C++ performs integer division and discards any fractional part, so 10 / 3 truncates to 3. When at least one operand is a floating-point type, the division is carried out using floating-point arithmetic and keeps the fractional part, so 10.0 / 3.0 produces approximately 3.333333.

Why is the expression ptr != nullptr && *ptr == 10 safe even when ptr might be a null pointer?

&& uses short-circuit evaluation: if the left operand (ptr != nullptr) is false, the right operand (*ptr == 10) is never evaluated at all, so a null pointer is never dereferenced. The overall expression is false as soon as the left side is false.

What values are printed by std::cout << x++ << '\n'; std::cout << x << '\n'; if x starts at 5, and why do the two lines differ?

The output is 5 then 6. Postfix x++ yields the current value of x (5) for use in the expression and only afterward increments x to 6, so the first line prints the old value while the second line prints the already-updated x.

What is the difference between the logical AND operator && and the bitwise AND operator &, and when would each be appropriate?

&& is a logical operator: it takes two conditions (implicitly convertible to bool), evaluates them as true/false, and short-circuits — the right side is skipped if the left side is false. Use it to combine Boolean conditions, such as in an if statement. & is a bitwise operator: it operates on the individual bits of integral operands and always evaluates both operands. Use it for bit masking, testing, or manipulating flags, not for combining logical conditions.

What value does this print? Work through operator precedence and integer division step by step.

It prints 5. Step by step: a % b is 5 % 2 = 1. a / b is 5 / 2 = 2 (integer division). 2 * b is 2 * 2 = 4. Then 1 + 4 = 5.

Write a program that reads an integer from the user and prints "Even" if it is divisible by 2 and "Odd" otherwise, using the remainder operator.

The program reads number, then uses number % 2 == 0 to test whether the remainder after dividing by 2 is zero, which is true exactly when number is even.

What three values does this print, in decimal? Compute the bitwise AND, OR, and XOR of a and b bit by bit.

It prints 8 14 6. Bit by bit: a = 1010, b = 1100. a & b = 1000, which is decimal 8. a | b = 1110, which is decimal 14. a ^ b = 0110, which is decimal 6.

Write a program that uses the conditional operator ?: to store the larger of two integers x and y into a variable named larger, then prints it.

x > y ? x : y evaluates the condition x > y; since it is false here (7 is not greater than 12), the expression selects y, so larger is 12 and that is what gets printed.

Operands + Operators
        |
        v
     Expression
        |
        v
   Evaluation
        |
        v
 Result + possible side effects
int result = (a + b) * c;
int a = 5;
int b = 2;
int result = a % b + a / b * b;
std::cout << result;
unsigned int a = 0b1010;
unsigned int b = 0b1100;
std::cout << (a & b) << ' ' << (a | b) << ' ' << (a ^ b);