CLA (C language) study materials
CLA (C language) study resources

CLA (C language): C Essentials 2 (C102): Conversions, Bitwise Operators, Storage Classes and Recursion

CLA (C language) · Work through your exam, one topic at a time.

All guide sections

C Essentials 2 (C102): Conversions, Bitwise Operators, Storage Classes and Recursion

Domain 2 - C Essentials 2 goes below the syntax into the machine model: how values convert between types, how bits are manipulated, where objects live and how long they live, and how recursive calls consume the stack. Items ask you to predict the results of conversions, masks and storage-class behaviour.

Conversions and promotions

Operands of rank below int (char, short, bit-fields) are promoted to int before arithmetic. Then the usual arithmetic conversions apply: a double or float operand converts the other side to floating point; otherwise the lower integer rank (int < long < long long) converts to the higher. If one operand is unsigned with rank at least that of the signed one, the signed operand converts to unsigned - -1 < 1u is false. Casts truncate; signed overflow is undefined behaviour while unsigned wraps modulo 2^N.

Bitwise operators

& | ^ ~ work on the integer representation, and <</>> shift it. Idioms: set bit n with x |= 1u << n, clear with x &= ~(1u << n), test with x & (1u << n), toggle with ^=. Shifting by a negative count or by at least the type width is undefined; right-shifting a negative value is implementation-defined. Bitwise operators bind tighter than && but looser than ==, so parentheses are usually needed.

Scope, linkage and lifetime

auto is the default for block variables. static at block scope gives static storage duration: initialized once, the value persists between calls. static at file scope gives internal linkage, hiding the name from other translation units, while extern declares an object defined elsewhere. register is only a hint and forbids taking the address. Recursion needs a base case; each call allocates a frame, so deep recursion overflows the stack.

Worked example

unsigned bits(unsigned x){ unsigned c = 0; while (x) { x &= x - 1; c++; } return c; } Each x & (x-1) clears the lowest set bit, so the loop runs once per set bit rather than once per bit position. Declaring the parameter unsigned avoids sign extension if the body is later changed to use >>=.

Traps

sizeof yields size_t, so sizeof(int) - 1 > 0 is always true. Expecting a block-scope static to be re-initialized on each call; shifting by the type width; typing && where & is meant; assuming a bare extern int x; allocates storage.