Skip to content

C Operators — Arithmetic, Relational, Logical, Bitwise, and Assignment

DodaTech Updated 2026-06-28 10 min read

In this tutorial, you will learn about C Operators. We cover key concepts, practical examples, and best practices to help you master this topic.

C operators are symbols that perform operations on operands, including arithmetic for calculations, relational for comparisons, logical for Boolean conditions, bitwise for direct bit manipulation, and assignment for storing values.

Why It Matters

Operators are the building blocks of all computation in C. Every program calculates values, compares data, makes decisions, and manipulates memory. C provides a rich set of operators that map directly to CPU instructions, giving you fine-grained control over performance. Understanding operator precedence and associativity prevents subtle bugs that are hard to find.

Real-World Use

Device drivers use bitwise operators to set and clear individual bits in hardware registers. Network code uses shift operators to pack and unpack protocol headers. Security scanning tools like Durga Antivirus Pro use bitwise operations for fast pattern matching and checksum calculations. Database systems use relational operators in query filters.

What You Will Learn

  • Arithmetic operators for basic math operations
  • Relational operators for comparing values
  • Logical operators for combining conditions
  • Bitwise operators for bit-level manipulation
  • Assignment operators and compound assignments
  • Operator precedence and associativity rules

Learning Path

flowchart LR
  A[Constants] --> B[Operators
You are here] B --> C[Control Flow] C --> D[Loops] D --> E[Arrays] style B fill:#f90,color:#fff

Arithmetic Operators

C provides the standard arithmetic operators:

#include <stdio.h>

int main() {
    int a = 10, b = 3;
    
    printf("a + b = %d\n", a + b);  // 13
    printf("a - b = %d\n", a - b);  // 7
    printf("a * b = %d\n", a * b);  // 30
    printf("a / b = %d\n", a / b);  // 3 (integer division)
    printf("a %% b = %d\n", a % b);  // 1 (modulus)
    
    // Division with floating point
    double x = 10.0, y = 3.0;
    printf("x / y = %.2f\n", x / y);  // 3.33
    
    // Integer division truncates toward zero
    printf("-10 / 3 = %d\n", -10 / 3);  // -3 (truncates toward zero)
    
    return 0;
}

Expected output:

a + b = 13
a - b = 7
a * b = 30
a / b = 3
a % b = 1
x / y = 3.33
-10 / 3 = -3

Integer Division Rules

Dividing two integers yields an integer result. The fractional part is truncated (discarded). This is a common source of bugs:

int percent = (50 / 100) * 100;  // 0, not 50!
int correct = (50 * 100) / 100;  // 50

To get a floating-point result, make at least one operand a float or double:

double result = 10 / (double)3;  // 3.333...

Modulus Operator

The % operator returns the remainder of division. It works only with integer types:

int remainder = 17 % 5;  // 2 (because 5*3=15, remainder 2)

Relational Operators

Relational operators compare values and return 1 (true) or 0 (false):

#include <stdio.h>

int main() {
    int a = 5, b = 10;
    
    printf("a == b: %d\n", a == b);  // 0 (false)
    printf("a != b: %d\n", a != b);  // 1 (true)
    printf("a < b: %d\n", a < b);    // 1 (true)
    printf("a > b: %d\n", a > b);    // 0 (false)
    printf("a <= b: %d\n", a <= b);  // 1 (true)
    printf("a >= b: %d\n", a >= b);  // 0 (false)
    
    return 0;
}

Expected output:

a == b: 0
a != b: 1
a < b: 1
a > b: 0
a <= b: 1
a >= b: 0

In C, any non-zero value is considered true in a Boolean context. Zero is false. Relational operators always return 0 or 1.

Logical Operators

Logical operators combine Boolean expressions:

#include <stdio.h>

int main() {
    int age = 25;
    int has_license = 1;  // true
    int is_sunday = 0;    // false
    
    // AND: both must be true
    if (age >= 18 && has_license) {
        printf("Can drive\n");
    }
    
    // OR: at least one must be true
    if (is_sunday || age >= 18) {
        printf("Can go out\n");
    }
    
    // NOT: inverts the condition
    if (!is_sunday) {
        printf("Not Sunday\n");
    }
    
    // Short-circuit evaluation
    // If the first condition is false with &&, 
    // the second is never evaluated
    int x = 0;
    if (x != 0 && 10 / x > 2) {
        printf("This never executes\n");
    }
    
    return 0;
}

Expected output:

Can drive
Can go out
Not Sunday

Short-Circuit Evaluation

The && and || operators use short-circuit evaluation. For &&, if the left operand is false, the right operand is not evaluated. For ||, if the left operand is true, the right operand is not evaluated. This is crucial for writing safe conditions like checking for NULL before dereferencing.

Bitwise Operators

Bitwise operators manipulate individual bits in integer values:

#include <stdio.h>

int main() {
    unsigned int a = 0b1100;  // 12 in binary
    unsigned int b = 0b1010;  // 10 in binary
    
    printf("a & b  = %u (0b%04b)\n", a & b, a & b);     // 8 (1000)
    printf("a | b  = %u (0b%04b)\n", a | b, a | b);     // 14 (1110)
    printf("a ^ b  = %u (0b%04b)\n", a ^ b, a ^ b);     // 6 (0110)
    printf("~a     = %u\n", ~a);                          // bitwise NOT
    printf("a << 1 = %u (0b%04b)\n", a << 1, a << 1);   // 24 (11000)
    printf("a >> 1 = %u (0b%04b)\n", a >> 1, a >> 1);   // 6 (0110)
    
    return 0;
}

Expected output:

a & b  = 8 (0b1000)
a | b  = 14 (0b1110)
a ^ b  = 6 (0b0110)
~a     = 4294967283
a << 1 = 24 (0b11000)
a >> 1 = 6 (0b0110)

Common Bitwise Patterns

// Set bit N (0-indexed)
x |= (1 << N);

// Clear bit N
x &= ~(1 << N);

// Toggle bit N
x ^= (1 << N);

// Check bit N
if (x & (1 << N)) { ... }

// Check if power of 2
if (x && !(x & (x - 1))) { ... }

// Check if even/odd
if (x & 1) { /* odd */ } else { /* even */ }

Assignment Operators

Simple assignment = and compound assignment operators:

#include <stdio.h>

int main() {
    int x = 10;
    
    x += 5;   // x = x + 5  -> 15
    x -= 3;   // x = x - 3  -> 12
    x *= 2;   // x = x * 2  -> 24
    x /= 4;   // x = x / 4  -> 6
    x %= 3;   // x = x % 3  -> 0
    
    int y = 0b1100;
    y &= 0b1010;   // y = y & 0b1010 -> 8
    y |= 0b0001;   // y = y | 0b0001 -> 9
    y ^= 0b0011;   // y = y ^ 0b0011 -> 10
    y <<= 1;       // y = y << 1    -> 20
    y >>= 2;       // y = y >> 2    -> 5
    
    printf("x: %d\n", x);
    printf("y: %d\n", y);
    
    return 0;
}

Expected output:

x: 0
y: 5

Increment and Decrement Operators

The ++ and -- operators add or subtract 1:

#include <stdio.h>

int main() {
    int x = 5;
    
    // Prefix: increment, then use
    int y = ++x;  // x becomes 6, y becomes 6
    printf("Prefix: x=%d, y=%d\n", x, y);
    
    // Postfix: use, then increment
    int a = 5;
    int b = a++;  // b becomes 5, a becomes 6
    printf("Postfix: a=%d, b=%d\n", a, b);
    
    // Common usage
    for (int i = 0; i < 5; i++) {
        printf("%d ", i);
    }
    printf("\n");
    
    return 0;
}

Expected output:

Prefix: x=6, y=6
Postfix: a=6, b=5
0 1 2 3 4

Operator Precedence

When multiple operators appear in an expression, precedence determines the order of evaluation:

#include <stdio.h>

int main() {
    int result;
    
    // Multiplication before addition
    result = 5 + 3 * 4;     // 17, not 32
    printf("5 + 3 * 4 = %d\n", result);
    
    // Use parentheses to override
    result = (5 + 3) * 4;   // 32
    printf("(5 + 3) * 4 = %d\n", result);
    
    // Relational vs logical
    result = 5 > 3 && 2 < 4;  // 1 (true)
    printf("5 > 3 && 2 < 4 = %d\n", result);
    
    // Bitwise vs comparison
    result = 5 & 3 == 1;  // 5 & (3 == 1) -> 5 & 0 -> 0
    printf("5 & 3 == 1 = %d\n", result);
    result = (5 & 3) == 1;  // (1) == 1 -> 1
    printf("(5 & 3) == 1 = %d\n", result);
    
    return 0;
}

Expected output:

5 + 3 * 4 = 17
(5 + 3) * 4 = 32
5 > 3 && 2 < 4 = 1
5 & 3 == 1 = 0
(5 & 3) == 1 = 1

Precedence Table (Highest to Lowest)

  1. () [] -> . (postfix)
  2. ++ -- + - ! ~ * & sizeof (unary, R-to-L)
  3. * / % (multiplicative)
  4. + - (additive)
  5. << >> (shift)
  6. < <= > >= (relational)
  7. == != (equality)
  8. & (bitwise AND)
  9. ^ (bitwise XOR)
  10. | (bitwise OR)
  11. && (logical AND)
  12. || (logical OR)
  13. ?: (conditional, R-to-L)
  14. = += -= etc. (assignment, R-to-L)
  15. , (comma)

Common Mistakes

1. Using = Instead of ==

if (x = 5)  // Always true! Assigns 5 to x, then tests x

Use == for comparison. Some compilers warn about this with -Wall.

2. Assuming Logical AND is the Same as Bitwise AND

if (x & 2)  // Bitwise AND, not logical
if (x && 2) // Logical AND (both non-zero)

& is bitwise; && is logical. They behave differently with non-Boolean values.

3. Integer Division Confusion

double ratio = 1 / 3;  // 0.0, not 0.333

Use 1.0 / 3 or cast one operand: (double)1 / 3.

4. Precedence Mistakes

if (x & 0x01 == 0)  // Evaluated as x & (0x01 == 0) -> x & 0 -> 0

Always use parentheses with bitwise operators in conditions.

5. Side Effects in Macro Arguments

#define SQR(x) ((x)*(x))
int y = SQR(++x);  // UB: x is modified twice

Never pass expressions with side effects to macros that evaluate the argument multiple times.

Practice Questions

  1. What is the output of 5 / 2 in C? 2 -- integer division truncates the fractional part.

  2. What does the % operator do? It returns the remainder of integer division. 5 % 2 is 1.

  3. What is short-circuit evaluation? For && and ||, the right operand is not evaluated if the left operand determines the result.

  4. How do you set, clear, and toggle specific bits? Set: x |= (1 << n), Clear: x &= ~(1 << n), Toggle: x ^= (1 << n).

  5. Challenge: Write a program that counts the number of 1 bits in an integer without using a loop (hint: use a trick like x & (x-1)).

Mini Project: Bit Manipulation Utility

Create a program that prints the binary representation of integers and demonstrates bit manipulation:

#include <stdio.h>
#include <limits.h>

void print_binary(unsigned int x) {
    for (int i = sizeof(x) * CHAR_BIT - 1; i >= 0; i--) {
        putchar((x & (1u << i)) ? '1' : '0');
        if (i % 4 == 0) putchar(' ');
    }
    putchar('\n');
}

int main() {
    unsigned int value = 42;
    
    printf("Original: ");
    print_binary(value);
    
    value |= (1 << 3);  // Set bit 3
    printf("Set bit 3: ");
    print_binary(value);
    
    value &= ~(1 << 5);  // Clear bit 5
    printf("Clear bit 5: ");
    print_binary(value);
    
    value ^= (1 << 1);  // Toggle bit 1
    printf("Toggle bit 1: ");
    print_binary(value);
    
    return 0;
}

FAQ

What is the difference between logical AND (&&) and bitwise AND (&)?

&& returns 0 or 1 based on Boolean truth. & performs bitwise operation on each bit position. && short-circuits; & does not.

Why does 1/2 equal 0 in C?

Integer division truncates the fractional part. Use floating-point literals: 1.0/2.0 equals 0.5.

What is the comma operator?

It evaluates both operands and returns the second. For example: int x = (a=1, a+5); sets x to 6.

Can I overload operators in C?

No. Operator overloading is a C++ feature. C does not allow redefining operator behavior.

What is the sizeof operator?

sizeof returns the size of a type or expression in bytes. It is evaluated at compile time, not runtime.

What is Next

Now that you understand operators, proceed to Control Flow to learn how to use if/else, switch, and conditional expressions to control program execution.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro

Home Browse C