Tutorials Logic, IN info@tutorialslogic.com

C Operators Arithmetic, Bitwise, Ternary

Expression Evaluation

C operators combine values into expressions, but the visible symbol is only part of the rule. Operand types control conversions, precedence controls grouping, short-circuit operators control whether the right operand runs, and side effects can make an expression undefined when the same scalar is modified and reused without sequencing.

After this lesson, you can predict the type and value of common expressions, add parentheses where intent matters, distinguish logical from bitwise operations, and rewrite compact expressions whose evaluation order would be unsafe or difficult to review.

Arithmetic Conversions

The arithmetic operators are +, -, *, /, and %. Integer division discards the fractional part toward zero, so 7 / 2 produces 3 while 7.0 / 2 produces 3.5. The remainder operator requires integer operands. Division or remainder by zero is invalid and must be prevented before evaluating the expression.

Before many binary operations, integer promotions and the usual arithmetic conversions bring operands to a common type. Mixing signed and unsigned values can therefore produce a surprising unsigned comparison or result. Use types that represent the domain, validate ranges, and convert deliberately at a boundary instead of scattering casts that hide warnings.

Comparison Results

Relational operators compare ordering, and equality operators compare equality. Their result is an int with value 1 for true or 0 for false. Do not confuse assignment = with equality ==. A compiler warning level that diagnoses assignment used as a condition catches many accidental cases.

Floating-point values often contain rounding error, so exact equality is appropriate only when the program logic guarantees identical representations. For measured or calculated values, compare according to an error policy that matches the scale and domain rather than using one universal epsilon.

Logical Short Circuit

The logical operators !, &&, and || treat zero as false and nonzero as true, and produce 0 or 1. && evaluates its right operand only when the left operand is true. || evaluates its right operand only when the left operand is false. This sequencing supports guarded access such as pointer != NULL && pointer->ready.

Use short-circuiting to protect a required precondition, not to hide a large state-changing operation inside a condition. Pull complex side effects into named statements so debugging and error handling remain visible.

Bitwise Operations

Bitwise &, |, ^, ~, <<, and >> operate on integer representations. They are useful for masks, flags, packed protocols, device registers, and powers-of-two transformations. They do not perform boolean short-circuiting: both operands of & and | are evaluated.

Prefer unsigned integer types for bit manipulation so shifts and complements are easier to reason about. Validate the shift count; shifting by a negative count or by a count greater than or equal to the width of the promoted left operand is invalid. Do not assume a packed bit layout is portable across protocols without defining widths and byte order.

Assignment and Update

Simple assignment stores a converted right-hand value in a modifiable left operand. Compound assignment such as total += amount reads, combines, converts, and stores while evaluating the left operand once. Prefix ++i updates then yields the new value; postfix i++ yields the old value and still performs the update.

Keep one modification of a scalar in a full expression. Code such as i = i++ or a function call that both modifies and reads i through separate arguments has undefined behavior or unspecified ordering concerns depending on the exact expression. Split the work into statements with an obvious sequence.

Arithmetic, Relational and Logical Operators

Arithmetic, Relational and Logical Operators
#include <stdio.h>

int main() {
    int a = 10, b = 3;

    // Arithmetic
    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

    // Increment / Decrement
    int x = 5;
    printf("x++: %d\n", x++);  // 5 (post-increment: use then increment)
    printf("x:   %d\n", x);    // 6
    printf("++x: %d\n", ++x);  // 7 (pre-increment: increment then use)

    // Relational
    printf("\n5 == 5: %d\n", 5 == 5);  // 1
    printf("5 != 3: %d\n",  5 != 3);  // 1
    printf("5 > 8:  %d\n",  5 > 8);   // 0

    // Logical
    int age = 20;
    printf("\nage >= 18 && age <= 60: %d\n", age >= 18 && age <= 60);  // 1
    printf("age < 18 || age > 60:   %d\n",  age < 18 || age > 60);   // 0
    printf("!(age == 20):           %d\n",  !(age == 20));            // 0

    return 0;
}

Bitwise, Ternary and sizeof Operators

Bitwise, Ternary and sizeof Operators
#include <stdio.h>

int main() {
    int a = 5, b = 3;  // a = 0101, b = 0011 in binary

    // Bitwise operators
    printf("a & b  = %d\n", a & b);   // 1  (0001)
    printf("a | b  = %d\n", a | b);   // 7  (0111)
    printf("a ^ b  = %d\n", a ^ b);   // 6  (0110)
    printf("~a     = %d\n", ~a);      // -6
    printf("a << 1 = %d\n", a << 1); // 10 (multiply by 2)
    printf("a >> 1 = %d\n", a >> 1); // 2  (divide by 2)

    // Ternary operator: condition ? value_if_true : value_if_false
    int num = 7;
    char *result = (num % 2 == 0) ? "even" : "odd";
    printf("\n%d is %s\n", num, result);  // 7 is odd

    int max = (a > b) ? a : b;
    printf("Max of %d and %d is %d\n", a, b, max);  // 5

    // sizeof operator
    printf("\nsizeof(int):    %zu\n", sizeof(int));
    printf("sizeof(double): %zu\n", sizeof(double));
    printf("sizeof(a):      %zu\n", sizeof(a));  // same as sizeof(int)

    return 0;
}

Precedence and Intent

Precedence determines how an unparenthesized expression groups; associativity resolves operators at the same precedence level. Neither rule generally promises which operand runs first. Parentheses document grouping but do not invent an evaluation order between function arguments or ordinary arithmetic operands.

The conditional operator condition ? yes : no evaluates only one of its second or third operands. It works well for a small value choice. Use if and else when branches need multiple statements, separate error handling, or comments.

Make Grouping Explicit

Make Grouping Explicit
#include <stdio.h>

int main(void) {
    int flags = 0x05;
    int required = 0x01;
    int enabled = (flags & required) != 0;
    int score = 72;
    const char *result = score >= 60 ? "pass" : "retry";

    printf("enabled=%d, result=%s\n", enabled, result);
    return 0;
}
Output
enabled=1, result=pass

Parentheses make the mask operation happen before comparison. The conditional operator selects one string and evaluates only the selected branch.

Before you move on

Expression Review

5 checks
  • Determine the promoted operand types before predicting the result.
  • Guard division, remainder, pointer access, and shift counts before evaluation.
  • Use && and || for logical short-circuiting and bitwise operators for masks.
  • Add parentheses for grouping and split ambiguous side effects into statements.
  • Enable compiler warnings and treat suspicious conversions as design feedback.

Operator Traps

  • Expecting 7 / 2 to be 3.5

    Make at least one operand floating-point when fractional division is intended.
  • Using & instead of &&

    Use logical operators for conditions; bitwise operators evaluate both integer operands.
  • Updating one variable twice

    Separate modifications into sequenced statements with one clear result each.

Try this next

Trace the Expressions

0 of 3 completed

  1. Evaluate integer and floating divisions, then confirm the printed types and values.
  2. Set, clear, toggle, and test three named unsigned flags.
  3. Rewrite three expressions that combine increment with another read of the same variable.

Operator Decisions

They control grouping, but most operators still do not specify whether the left or right operand is evaluated first.

Unsigned arithmetic has defined modulo behavior and avoids many signed-shift and sign-extension surprises.

No, but it is easy to confuse with equality. Use it only when intentional, parenthesized, and clear to reviewers.

Next Step
Next Practice

Finish the concept here, then reinforce it with hands-on coding, interview prep, or a tool that matches the topic.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.