A scientific calculator photographed in low light. Photo · Harshil Prajapati / Unsplash
Every operator is a button. The chef has about thirty of them. Together, they cover every calculation a computer has ever done.

Variables sit on the counter. Operators are how you do things to them — add, multiply, compare, manipulate. C has roughly thirty operators, and almost every one of them survived, unchanged, into every modern language. + for plus. % for modulo. && for AND. ?: for "if-this-then-that-else-the-other". You'll meet them again in JavaScript, Java, Python, Swift, Go, Rust, Kotlin — same symbols, same meanings.

The operators themselves are the easy part. The interesting part is the traps: integer overflow, integer-vs-float division, operator precedence, the difference between = and ==. We'll cover the operators, then we'll cover the traps. The traps cause more bugs than the operators do work.

The five families

Arithmetic

The math you already know — but on integers, with one twist (%).

+
add
7 + 3 → 10
-
subtract
7 - 3 → 4
*
multiply
7 * 3 → 21
/
divide
7 / 3 → 2 (int!)
%
modulo (remainder)
7 % 3 → 1

Comparison

Each one returns 1 if true, 0 if false.

==
equal to
x == 5
!=
not equal to
x != 0
<
less than
x < 10
<=
less than or equal
x <= 10
>
greater than
x > 0
>=
greater than or equal
x >= 0

Logical (combine truths)

&&
AND — both must be true
x > 0 && x < 10
||
OR — at least one true
x == 0 || y == 0
!
NOT — flip true/false
!found

Bitwise (operate on individual bits)

&
bit AND
0b1100 & 0b1010 → 0b1000
|
bit OR
0b1100 | 0b1010 → 0b1110
^
bit XOR
0b1100 ^ 0b1010 → 0b0110
~
bit NOT (flip every bit)
~0b1100 → 0b...0011
<<
shift left (×2)
5 << 2 → 20
>>
shift right (÷2)
20 >> 2 → 5

Assignment

=
store on the right into the left
x = 5
+=
add right to left
x += 3 (same as x = x + 3)
-= *= /= %=
same idea
total *= 2
++ --
add or subtract 1 in place
x++ (most common loop step)

Trap one: 5 / 2 isn't 2.5

This is the single most common beginner C bug.

int a = 5;
int b = 2;
double avg = a / b;     // avg is 2.0, NOT 2.5 !

Why? Because a and b are both int. C looks at the operator /, looks at its two operands, and picks integer division — which throws away the fractional part. The result is 2. Only then does that 2 get converted to a double (2.0) for assignment.

The fix: tell the compiler that at least one operand is floating-point.

double avg = (double)a / b;    // 2.5 ✓
// or
double avg2 = a / 2.0;          // 2.5 ✓

Once one side is floating-point, the other is converted up, and you get real division.

Trap two: integer overflow

What happens when an int can't hold the result?

int x = 2147483647;   // the largest 32-bit signed int
x += 1;
printf("%d\n", x);     // prints -2147483648 (!!)

Adding 1 to the maximum signed 32-bit integer doesn't give you the next number — it wraps around to the most negative value the type can hold. The chef does it silently. There's no exception, no warning, just a number that has slipped through the floor of the world.

This is one of the most consequential properties of C. Many real-world security bugs (Heartbleed-class, integer-overflow-into-buffer-overflow vulnerabilities) start exactly here. Modern C codebases use -fsanitize=undefined in development builds to catch this; production C uses smaller types defensively or wraps risky math in checked-arithmetic helpers. Higher-level languages (Python, Swift) detect overflow automatically — and pay a runtime cost for doing so.

For floating-point, a similar but gentler thing happens: numbers don't wrap, but precision is lost silently. 0.1 + 0.2 in any IEEE-754 language gives 0.30000000000000004. This is not a C bug; it's how binary floating-point works.

Trap three: = vs ==

One equals sign means assign. Two means compare. C will helpfully let you confuse them and silently turn a comparison into an assignment.

if (x = 5) {          // always true!  x is now 5
    printf("yes!\n");
}

That code compiles, runs, and prints "yes!" every time. The condition x = 5 is an assignment — its value is 5, which is non-zero, which counts as "true". Modern compilers warn (-Wall will catch it: "suggest parentheses around assignment"), but they only warn — they don't refuse.

Many C codebases adopt the "Yoda condition" style to make this impossible: if (5 == x). You can't accidentally assign 5 to a literal, so the compiler refuses. Some find Yoda style ugly. Both sides have a point.

Operator precedence — the order things happen

C has rules about which operator binds tightest. They mostly match school algebra: * and / bind tighter than + and -. So 2 + 3 * 4 is 14, not 20. So far, so familiar.

But there are corners that surprise everyone, even experienced C programmers:

The professional rule: when in doubt, parenthesise. Compilers don't charge per parenthesis. Readers do, in cognitive load when they're not there.

Short-circuit evaluation

The logical operators && and || have a useful, slightly magic property. C evaluates the left side first; if the answer is already determined, the right side is never evaluated.

// safe pointer check — short circuits if p is NULL:
if (p != NULL && p->value == 42) { /* ... */ }

If p is null, p != NULL is false, and the &&'s right side never runs — so the dangerous dereference p->value never happens. Without short-circuiting, you'd crash. This idiom is everywhere in real C; it's also why "always evaluate both sides" is a real, occasionally annoying, feature of some languages and not C.

Why this matters for AI

Every neural-network training loop does, somewhere down the bottom of its inner loop, weight = weight - learning_rate * gradient. That single line, repeated trillions of times, is what training is. Floating-point precision matters here: float's 7 significant decimal digits is sometimes too coarse, which is why training uses tricks like "mixed precision" (FP16 for speed, FP32 for accumulators) and "loss scaling" (multiply gradients by 1024 before storing them, divide back later — to keep the small values in range).

And every time you've heard of an LLM "going crazy with NaNs" — somebody hit floating-point overflow or underflow in a mathematical operation that should have been bounded. The chef did exactly what was asked, with no safety net. Welcome to numerical computing.

Operators are simple. The numbers they touch are surprising. The bugs are at the boundary.

Try it yourself

What's next

Now we can compute things. Next week we make the computer decide: do this if that's true, otherwise do this other thing. Three lines from here, you'll have built the conceptual atom of every algorithm ever written.

Week 14 is The Fork in the Roadif, else, and the boolean logic at the heart of every program.

Photo credit

Photo free under the Unsplash license. Calculator · Harshil Prajapati.