Operators and Expressions: Arithmetic, Relational, Logical, Bitwise, Assignment, Increment/Decrement, Precedence and Type Conversion
This domain tests whether you can evaluate a C expression exactly as the compiler does: which operator binds tighter, what type each intermediate result has, and where undefined behaviour lurks.
Arithmetic and relational
Binary + - * / and %. Integer division truncates toward zero: 7/2 is 3, -7/2 is -3 and -7%2 is -1. The % operator requires integer operands. Relational operators < <= > >= == != yield int 0 or 1.
Logical and bitwise
&&, || and ! treat zero as false and non-zero as true, and they short-circuit: in a != 0 && b / a > 1 the division never executes when a is 0. Bitwise & | ^ ~ << >> act on the binary representation. Shifting a negative value, or shifting by at least the operand width, is undefined; use unsigned types when shifting.
Assignment, increment and precedence
= is right-associative and yields the assigned value, so a = b = 0 works. ++ and -- have prefix (change, then yield) and postfix (yield, then change) forms. Precedence from high to low: postfix, unary, * / %, + -, shifts, relational, equality, &, ^, |, &&, ||, ?:, assignment, comma. i = i++ modifies i twice with no intervening sequence point - undefined behaviour, never a valid answer.
Type conversion
char and short are promoted to int in expressions; when operands differ, the narrower type is converted to the wider one (the usual arithmetic conversions). Force a conversion with a cast.
Worked example
int a = 7, b = 2; float f = a / b; stores 3.0, because a / b is integer division performed before the assignment. Writing float f = (float)a / b; stores 3.5.
Traps
if (x = 5)assigns and is always true;if (x == 5)compares.!is logical negation;~is bitwise complement.a << 1is not a reliable multiply-by-two for signed values near overflow.x += ycan differ fromx = x + ywhenxhas side effects.