Operators & Expressions
Arithmetic, comparison, logical, and bitwise operators — plus the = vs == trap
Quick check before you start: Do you know what
^does in C? (Hint: it is not exponentiation.) If not, read on. If you can explain it, skip to Precedence.Practice this topic: C Operators skill drill
After this lesson, you will be able to:
- Use arithmetic, comparison, and logical operators in expressions
- Apply bitwise operators for bit-level manipulation
- Use
sizeofto determine the size of a type or variable - Explain why
=and==are different and how confusing them causes bugs
Arithmetic Operators
Same as Java, with one critical difference: integer division truncates.
int a = 7, b = 3;
printf("%d\n", a + b); /* 10 */
printf("%d\n", a - b); /* 4 */
printf("%d\n", a * b); /* 21 */
printf("%d\n", a / b); /* 2, not 2.333 */
printf("%d\n", a % b); /* 1 */
Increment and decrement work the same way: i++ (post), ++i (pre), i--, --i. In standalone statements, the difference does not matter. In expressions, it does.
Comparison & Logical Operators
C has no boolean type (before C99). Zero is false, and any non-zero value is true.
int x = 5, y = 10;
printf("%d\n", x < y); /* 1 (true) */
printf("%d\n", x == y); /* 0 (false) */
printf("%d\n", x != y); /* 1 (true) */
printf("%d\n", x > 0 && y > 0); /* 1 — logical AND */
printf("%d\n", x > 0 || y < 0); /* 1 — logical OR */
printf("%d\n", !(x > 0)); /* 0 — logical NOT */
Key Insight: C uses short-circuit evaluation. In
a && b, ifais 0,bis never evaluated. Ina || b, ifais non-zero,bis never evaluated. This matters whenbhas side effects.
Bitwise Operators
These operate on individual bits. You will use them in systems programming and CTF challenges.
| Operator | Name | Example | Result |
|---|---|---|---|
& |
AND | 0b1100 & 0b1010 |
0b1000 |
\| |
OR | 0b1100 \| 0b1010 |
0b1110 |
^ |
XOR | 0b1100 ^ 0b1010 |
0b0110 |
~ |
NOT | ~0b1100 |
0b...0011 |
<< |
left shift | 1 << 3 |
8 |
>> |
right shift | 16 >> 2 |
4 |
unsigned char flags = 0;
flags |= (1 << 2); /* set bit 2: flags = 00000100 */
flags |= (1 << 5); /* set bit 5: flags = 00100100 */
if (flags & (1 << 2)) {
printf("Bit 2 is set\n");
}
flags &= ~(1 << 2); /* clear bit 2: flags = 00100000 */
Left shift by n multiplies by 2^n. Right shift divides by 2^n (for unsigned values).
sizeof
sizeof returns the size in bytes of a type or variable. It is evaluated at compile time, not runtime.
printf("int: %zu bytes\n", sizeof(int)); /* 4 */
printf("double: %zu bytes\n", sizeof(double)); /* 8 */
printf("char: %zu bytes\n", sizeof(char)); /* 1 */
int arr[10];
printf("arr: %zu bytes\n", sizeof(arr)); /* 40 */
Use %zu for sizeof results — the return type is size_t, an unsigned integer.
The = vs == Trap
This is the single most common C bug for beginners.
int x = 5;
if (x = 0) { /* BUG: assigns 0 to x, then tests 0 (false) */
printf("zero\n");
}
if (x == 0) { /* CORRECT: compares x to 0 */
printf("zero\n");
}
= is assignment. == is comparison. The assignment x = 0 evaluates to 0, which is false. So the if-body never runs, and x is now 0. The compiler may warn you, but it is legal C. Some programmers write 0 == x (Yoda conditions) to catch this — 0 = x would be a compiler error.
Operator Precedence
You do not need to memorize the full table. Know these rules:
- Unary (
!,~,++,--,(type)) before binary - Arithmetic (
*,/,%) before (+,-) - Shift (
<<,>>) before comparison - Comparison (
<,>,<=,>=) before equality (==,!=) - Bitwise (
&before^before|) - Logical (
&&before||) - Assignment (
=,+=, etc.) is nearly last
When in doubt, use parentheses. (a + b) * c is clearer than relying on precedence.
if (x = 5) do in C?= is the assignment operator. x = 5 stores 5 in x and the expression evaluates to 5. Since 5 is non-zero, C treats it as true, so the if-body always executes. This is almost never what you want. Use == for comparison.
What Comes Next
You have the building blocks — variables, I/O, and operators. Next, you will combine them into decision-making and loops with if/else, switch, and the three loop forms.