OSC.003: C Operators and Expressions

C programming workspace showing arithmetic, relational, logical, bitwise, assignment, and precedence examples beside an embedded development board.

Operators are the symbols that tell C what to do with values. Expressions combine variables, constants, function results, and operators to calculate new values, compare conditions, manipulate individual bits, and update program state.

This lesson follows OSC.002: C Variables and Fundamental Types. That lesson established what C values and types are. OSC.003 focuses on how those values interact inside expressions.

Neso Academy introduces arithmetic operators in C, including addition, subtraction, multiplication, division, remainder, precedence, and associativity.

Elementary Overview

An expression is like a small calculation written inside a program. In total = price * quantity;, C first forms the expression on the right, then stores its result in total. The symbols = and * are operators, while price and quantity are operands.

Learning Objectives

  • Use arithmetic operators correctly with integer and floating-point values.
  • Explain integer division and the remainder operator.
  • Use relational and equality operators to produce true/false results.
  • Use &&, ||, and ! and explain short-circuit evaluation.
  • Distinguish logical operators from bitwise operators.
  • Use compound assignment without confusing it with comparison.
  • Read operator precedence and associativity correctly.
  • Explain why precedence does not define the complete runtime evaluation order of subexpressions.
  • Avoid expressions whose behavior is undefined because the same object is modified without a defined sequencing relationship.

Arithmetic Operators

The basic arithmetic operators are +, -, *, /, and %. The first four perform addition, subtraction, multiplication, and division. The remainder operator % is defined for integer operands and returns the remainder after integer division.

int a = 10;
int b = 3;

int sum = a + b;        // 13
int difference = a - b; // 7
int product = a * b;    // 30
int quotient = a / b;   // 3
int remainder = a % b;  // 1

When both operands of / are integers, C performs integer division. The fractional part is discarded toward zero. Therefore 10 / 3 produces 3, not 3.333.... If at least one operand has a floating-point type, the calculation is performed using the usual arithmetic conversions appropriate to the operands.

double q1 = 10 / 3;      // 3.0 because integer division happens first
double q2 = 10.0 / 3.0;  // approximately 3.333333

Relational and Equality Operators

C uses <, <=, >, >=, ==, and != to compare values. A comparison expression produces an integer result: zero represents false and one represents true for these operators.

int temperature = 72;

int warm = temperature > 70;
int exactly_72 = temperature == 72;
int not_freezing = temperature != 32;

Neso Academy demonstrates relational operators and the difference among equality and ordering comparisons.

A common beginner bug is confusing assignment with comparison. x = 5 assigns the value 5 to x. x == 5 compares x with 5. Compilers can warn about suspicious assignments inside conditions when warning options such as -Wall -Wextra are enabled.

Logical Operators and Short-Circuit Evaluation

The logical operators are && for logical AND, || for logical OR, and ! for logical NOT. C treats zero as false and any nonzero scalar value as true in a logical context. The result of these logical operators is either 0 or 1.

int powered = 1;
int network_ok = 1;

if (powered && network_ok) {
    /* both conditions are true */
}

&& and || are short-circuit operators. For A && B, C evaluates B only if A is true. For A || B, C evaluates B only if A is false. This behavior can safely guard operations that would otherwise be invalid.

if (x != 0 && (100 / x) > 5) {
    /* division occurs only when x is nonzero */
}

Neso Academy explains C logical operators and short-circuit behavior.

Bitwise Operators

Bitwise operators work on the individual bits of integer operands. They include & for bitwise AND, | for bitwise OR, ^ for bitwise XOR, ~ for bitwise complement, and << and >> for shifts.

unsigned int flags = 0x05;   // binary ...0101
unsigned int mask  = 0x01;

int bit0_set = (flags & mask) != 0;
flags |= 0x08;   // set bit 3
flags &= ~0x01u; // clear bit 0

Do not confuse & with &&, or | with ||. The bitwise forms operate on bits and evaluate both operands. The logical forms interpret operands as true/false conditions and can short-circuit.

Neso Academy introduces bitwise AND, OR, complement, and the distinction between bitwise and logical operators.

Assignment and Compound Assignment

The assignment operator = stores a value in a modifiable object. C also provides compound assignment forms such as +=, -=, *=, /=, %=, &=, |=, ^=, <<=, and >>=.

int count = 10;
count += 5;  // count becomes 15
count *= 2;  // count becomes 30

Neso Academy covers ordinary and shorthand assignment operators in C.

Precedence and Associativity

Operator precedence determines how tokens in an expression are grouped when parentheses do not state the grouping explicitly. For example, multiplication binds more tightly than addition, so a + b * c is parsed as a + (b * c). Parentheses are often the clearest way to show intended grouping.

Associativity matters when operators of the same precedence appear together. Addition and subtraction associate left to right, so a - b - c groups as (a - b) - c. Assignment associates right to left, so x = y = 0 groups as x = (y = 0).

Neso Academy explains C operator precedence, associativity, parentheses, and common increment/decrement cases.

Precedence Is Not Evaluation Order

This distinction is important. Precedence tells the compiler how an expression is grouped syntactically; it does not generally specify the order in which independent operand subexpressions are evaluated. In an expression such as f() + g() * h(), multiplication has higher precedence than addition, but that does not by itself require the calls to occur in the order g(), h(), then f().

A C programming discussion highlights an important standards point: prefix and postfix operators have defined precedence relationships, but precedence should not be confused with runtime sequencing.

Avoid Undefined Side-Effect Expressions

C gives programmers considerable freedom, but some compact expressions are not portable because they modify and access the same object without the sequencing required by the language rules. Code such as i = i++ + ++i; should not be treated as a puzzle to solve by operator precedence. Its behavior is undefined.

Prefer clear, separately sequenced statements:

i++;
int next = i + 1;
i = next;

Readable C is usually better C. Parentheses and separate statements make the programmer’s intent visible and reduce reliance on memorizing a long precedence table.

Practical Exercise

  1. Create a file named operators.c.
  2. Declare two integers and one floating-point variable.
  3. Print the results of +, -, *, /, and % for the integers.
  4. Repeat division using floating-point operands and compare the result.
  5. Create three comparison expressions and print their integer results.
  6. Write one short-circuit condition that safely guards division by zero.
  7. Use a bit mask to test, set, and clear one bit in an unsigned integer.
  8. Write one expression that depends on precedence, then rewrite it with explicit parentheses.
  9. Compile with gcc -Wall -Wextra -Wpedantic operators.c -o operators.
  10. Remove every compiler warning before considering the exercise complete.

Knowledge Check

  1. What does 10 / 3 produce when both operands are int?
  2. What is the difference between = and ==?
  3. What does % compute?
  4. What values represent false and true in C logical contexts?
  5. Why can && safely guard a division operation?
  6. What is the difference between & and &&?
  7. How does a + b * c group?
  8. Does operator precedence fully determine the runtime evaluation order of independent subexpressions?
  9. Why is i = i++ + ++i; not a valid precedence exercise?
  10. What compiler options used in this lesson help expose suspicious code?

Answers

  1. 3, because integer division discards the fractional part toward zero.
  2. = assigns a value; == compares two values for equality.
  3. The remainder from integer division.
  4. Zero is false; nonzero scalar values are treated as true. Logical operators themselves produce 0 or 1.
  5. The right operand is evaluated only if the left operand is true.
  6. & is bitwise AND; && is logical AND and short-circuits.
  7. a + (b * c).
  8. No. Precedence determines grouping, not the complete order of independent operand evaluation.
  9. It modifies the same object multiple times without the required sequencing, producing undefined behavior.
  10. -Wall -Wextra -Wpedantic.

Primary References

Elementary Conclusion

Operators tell C how values should interact. Arithmetic operators calculate, comparison operators test, logical operators combine conditions, bitwise operators manipulate individual bits, and assignment operators update objects. Precedence determines how expressions group, but it should never be confused with full evaluation order. When an expression becomes difficult to read, use parentheses or split it into simpler statements.

BitcoinVersus.Tech Editor’s Note:
We volunteer daily to ensure the credibility of the information on this platform is Verifiably True. If you would like to support to help further secure the integrity of our research initiatives, please donate using the QR code provided

Bitcoin donation QR code for 5,000 sats.

For best QR-code scanning results, please scan this donation code from a desktop or larger screen. Mobile screens may prevent camera recognition.

BitcoinVersus.Tech provides technical education and analysis for informational purposes only.

Leave a Reply