Chapter 05

Expressions, Statements and Operators

Arithmetic, comparison, logical, increment/decrement, compound assignment, bitwise operators, and std::bitset.

In this chapter

  1. Arithmetic Operators
  2. Comparison & Logical Operators
  3. Increment & Decrement
  4. Compound Assignment
  5. Bitwise Operators
  6. std::bitset
1

Arithmetic Operators

OperatorMeaningExample
+Addition5 + 3 → 8
-Subtraction5 - 3 → 2
*Multiplication5 * 3 → 15
/Division5 / 2 → 2 (integer division!)
%Modulo (remainder)5 % 2 → 1
Integer division truncates. 5 / 2 is 2, not 2.5. To get a floating-point result, cast at least one operand: (double)5 / 22.5.

2

Comparison & Logical Operators

Comparison

OperatorMeaning
==Equal to
!=Not equal to
<Less than
>Greater than
<=Less than or equal
>=Greater than or equal

Logical

OperatorMeaning
&&AND — both sides must be true
||OR — at least one side must be true
!NOT — inverts a boolean

Short-Circuit Evaluation

C++ stops evaluating a logical expression as soon as the result is determined:

int* ptr = nullptr;
if (ptr != nullptr && *ptr == 5) { // safe — *ptr never reached if ptr is null
    // ...
}

3

Increment & Decrement

Both ++ and -- come in two forms that differ in when the update happens relative to the expression being evaluated:

Post (value++)

The current value is used in the expression first, then the variable is incremented. Requires a temporary copy — slightly less efficient.

Pre (++value)

The variable is incremented first, then the new value is used. No temporary copy needed — preferred in loops and templates.

int a = 5;
int b = a++;  // b = 5, a = 6  (post: b gets old value)
int c = ++a;  // c = 7, a = 7  (pre:  c gets new value)
Prefer ++i over i++ in loop counters — the compiler often optimizes them identically for primitive types, but the habit matters for iterators and custom types.

4

Compound Assignment

Shorthand for applying an operator and assigning the result back to the same variable:

OperatorEquivalent
x += 3x = x + 3
x -= 3x = x - 3
x *= 3x = x * 3
x /= 3x = x / 3
x %= 3x = x % 3
x &= 3x = x & 3
x |= 3x = x | 3
x ^= 3x = x ^ 3
x <<= 1x = x << 1
x >>= 1x = x >> 1

5

Bitwise Operators

Bitwise operators work directly on the individual bits of integer types.

OperatorNameOperandsNotes
~NOTOneFlips all bits
&ANDTwo1 only if both bits are 1
|ORTwo1 if either bit is 1
^XORTwo1 only if bits differ
<<Shift LeftTwoEach shift multiplies by 2
>>Shift RightTwoEach shift divides by 2
Shift operators do not wrap around. Shifting a signed integer right has implementation-defined behavior — the sign bit may or may not be preserved. Prefer unsigned types for bit manipulation.
unsigned int x = 0b0000'1010;  // 10
x << 1;  // 0b0001'0100 = 20  (×2)
x >> 1;  // 0b0000'0101 = 5   (÷2)
~x;      // 0b1111'0101 = 245 (all bits flipped)

6

std::bitset

std::bitset<N> is a fixed-size sequence of bits. The template parameter N is the number of bits.

#include <bitset>

std::bitset<8> flags = 5; // 00000101 (binary of 5)

flags[0];        // 1 — LSB (least significant bit)
flags[7];        // 0 — MSB
flags.count();   // 2 — number of set bits
flags.flip(2);   // flip bit at position 2
std::cout << flags;  // prints "00000101"
Advantages over raw arrays
  • Can access bits individually
  • Prints directly with cout
  • Less memory (1 bit per entry vs 1 byte)
  • Built-in operations: count(), flip(), any(), all()
Limitations
  • Size is fixed at compile time
  • No arithmetic operations
← Chapter 4 ↑ Index Chapter 6 →