The Mechanics of Expressions
In C, an Expression is a sequence of operators and operands that specifies a computation. Understanding the nuances of how these expressions are evaluated is the difference between writing robust code and creating subtle, non-deterministic bugs.
Arithmetic Operators and Pitfalls
Common arithmetic operators (+, -, *, /, %) behave as expected for floating-point and unsigned integers. However, signed integer arithmetic carries risks:
- Integer Division: Truncates toward zero.
(-5) / 2results in-2. - The Modulo Operator (
%): Requires integer operands. The identity(a/b)*b + a%b == aalways holds in C.
Bitwise Operators: The Hardware Interface
C is the language of choice for drivers and embedded systems because of its direct support for bit-level manipulation.
| Operator | Description | Common Use Case |
|---|---|---|
& | Bitwise AND | Masking bits (clearing specific bits). |
| | Bitwise OR | Setting bits. |
^ | Bitwise XOR | Toggling bits or simple swaps. |
~ | Bitwise NOT | One’s complement (inverting all bits). |
<< | Left Shift | Multiply by power of 2. |
>> | Right Shift | Divide by power of 2 (Behavior for signed is implementation-defined). |
Interactive Lab
Waiting for signal...
Logical Operators and Short-Circuiting
Logical AND (&&) and OR (||) are guaranteed to evaluate from left-to-right. They use Short-Circuit Evaluation:
- In
A && B, ifAis false,Bis never evaluated. - In
A || B, ifAis true,Bis never evaluated.
This property is frequently used to guard against null pointer dereferences:
if (ptr != NULL && ptr->value > 10) { ... }
Precedence, Associativity, and Sequence Points
Precedence determines which operator is applied first in an expression like a + b * c. Associativity determines the direction of evaluation for operators of the same precedence (e.g., a - b - c is (a - b) - c).
The Sequence Point Rule
A “Sequence Point” is a point in time where all “side effects” (like variable assignments) from previous evaluations are guaranteed to be complete.
- The end of a statement (
;) is a sequence point. - The
&&,||, and,operators are sequence points.
CRITICAL RULE: Between two sequence points, an object’s value shall be modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored. Failure to follow this results in Undefined Behavior.
Sequence Point Violation
int i = 5;
// Is this code valid or undefined behavior?
i = i++ + 1;
// Answer: The Ternary Operator
The ?: operator is C’s only ternary operator. It is an expression, not a statement, meaning it returns a value and can be used on the right-hand side of an assignment.
int max = (a > b) ? a : b;