Free interview practice · Embedded C
Embedded C Interview Preparation
Technical questions with practical firmware reasoning, code examples and follow-ups. Built for engineers preparing for real interviews.
10 practice questions · Start by answering aloud before opening the explanation.
Q01 Why is volatile used for memory-mapped registers?
A peripheral may change a register outside normal program flow. A volatile-qualified access tells the compiler the register must be read or written as expressed, rather than assuming the value stays unchanged.
volatile uint32_t *status = (volatile uint32_t *)0x40000000u;Interview follow-up: Does volatile make a read-modify-write operation atomic? No.
Q02 Can two consecutive reads of a volatile register differ?
Yes. The peripheral may update status between the reads, and some registers clear flags on read. Consult the device reference manual before accessing a status register repeatedly.
uint32_t a = *status;
uint32_t b = *status;Interview follow-up: How would you handle a read-to-clear status register?
Q03 What is the difference between const volatile and volatile?
volatile means each access is observable to the compiler. const disallows modifications through that particular C lvalue. A read-only hardware status register is often declared const volatile.
const volatile uint32_t *status = (const volatile uint32_t *)0x40000000u;Interview follow-up: Does const prevent hardware from updating the register? No.
Q04 What happens if a pointer to a hardware register is not volatile?
The compiler may legally reuse an earlier value or hoist a read from a polling loop, depending on the code and optimization. Cast the register address to the correct volatile-qualified pointer type.
volatile uint32_t *reg = (volatile uint32_t *)0x40000000u;Interview follow-up: Is declaring the pointer variable volatile the same as declaring the pointed-to register volatile? No.
Q05 How do you set a bit without changing other bits?
Read the register, OR the bit mask, then write it back. This is a read-modify-write operation, which can be unsafe for write-one-to-clear registers and when another context updates the same register.
*control |= (1u << 3);Interview follow-up: What hardware atomic set/clear registers could you use instead?
Q06 How do you clear a bit using a mask?
AND the value with the inverse of the target bit mask. Confirm that the register permits normal read-modify-write access before using this pattern.
*control &= ~(1u << 3);Interview follow-up: Why is this incorrect for some write-one-to-clear registers?
Q07 What is the difference between a pointer and an address?
An address is a numeric location; a pointer is a typed value used by C to refer to an object or function. In embedded firmware, integer-to-pointer casts for peripheral addresses depend on platform mapping and implementation.
volatile uint32_t *reg = (volatile uint32_t *)0x40000000u;Interview follow-up: What does *reg mean in this statement?
Q08 Why does volatile not make shared data thread-safe?
Volatile does not provide atomicity or synchronization. A read-modify-write counter update can race, and coordination between tasks or cores needs the appropriate synchronization/atomic primitives.
counter++; /* not necessarily atomic */Interview follow-up: What changes when an ISR shares a flag with foreground code?
Q09 Why can structure padding matter in firmware?
The compiler may add padding between members for alignment, so the memory layout can differ from a wire protocol. Use explicit serialization instead of assuming a packed C structure matches UART/SPI packet bytes.
struct Packet { uint8_t type; uint32_t value; };Interview follow-up: How would you serialize a multi-byte value with defined byte order?
Q10 What happens if an interrupt occurs during a read-modify-write?
An ISR can update the same register or variable between the read and write, potentially losing one update. Consider atomic set/clear hardware, critical sections, or suitable synchronization based on context.
uint32_t t = *reg;
t |= BIT;
*reg = t;Interview follow-up: Why might disabling interrupts not solve a second-core race?