20 Embedded C Interview Questions with Practical Answers
These embedded C interview questions cover firmware reasoning rather than repeat the general C interview. There are exactly 20 questions (E1–E20). For a first introduction, read the embedded C overview. All peripheral and interrupt behavior must be checked against the specific board, compiler and device manual.

Target and language contracts
E1. How does embedded C differ from desktop C?
The core language can be the same, but firmware depends on its target ABI, startup code, linker layout, device headers and peripheral rules. Freestanding implementations need not provide all hosted-library services. A hosted online compiler cannot validate device timing or peripheral behavior.
E2. What happens before main in firmware?
Target startup code may set a stack pointer, initialize data sections, clear zero-initialized storage and configure the vector table before calling application code. Exact steps and whether main is even used depend on the toolchain and runtime; inspect the startup and linker files.
E3. What does volatile promise for a register?
It tells the implementation to treat accesses according to its volatile rules, which device toolchains use for externally observable storage. It does not by itself make the access atomic, order every nonvolatile operation, flush CPU caches, or provide a hardware memory barrier.
E4. Can volatile safely share data between an ISR and a task?
Not by itself. An access can tear, a read-modify-write can lose updates, and ordering may need platform barriers. Follow the MCU/compiler interrupt model; use suitable atomic operations or narrowly bounded critical sections where supported and safe.
E5. Why is a read-modify-write of a device register risky?
A peripheral or interrupt can change bits between the read and write. Some registers have write-one-to-clear, read-to-clear or reserved-bit semantics, making generic |= and &= inappropriate. Prefer documented set/clear aliases or the exact device-prescribed sequence.
E6. How do you create a safe bit mask?
Use an unsigned type wide enough for the target register and validate the shift count against the promoted operand width. For positions 0–7, 1u << bit is safe on every conforming C17 unsigned int. Wider device masks must be checked against that target’s integer widths.
E7. Can a packed struct portably represent a register block?
Not without toolchain and device guarantees. Layout, alignment, access width, endianness and bit-field allocation order can differ. Use the vendor header and documented accessor rules; a packing attribute is an extension and may create unsafe unaligned accesses.
E8. What do endianness and serialization change?
Endianness affects multi-byte object representation, while a protocol defines a byte order and field format. Encode/decode bytes explicitly for wire formats rather than sending a raw struct. State the protocol’s byte width assumptions and handle unaligned buffers safely.
E9. Why avoid dynamic allocation in some firmware?
Failure, fragmentation and variable execution time can conflict with tight memory and timing requirements. Static allocation or fixed-size pools can be easier to bound. This is a design trade-off, not a rule that every embedded system forbids malloc.
E10. How do you bound stack use?
Inspect call depth, automatic arrays, interrupt nesting and toolchain stack reports, then measure high-water marks under representative worst-case loads. Avoid unbounded recursion. A measurement alone cannot prove that an untested path fits.
E11. What should an interrupt handler do?
Acknowledge the source as the device requires, capture essential data and defer longer work. Keep execution bounded and use only ISR-safe services. Blocking, printf, or allocation can violate latency and reentrancy requirements depending on the runtime.
E12. How does DMA complicate buffer ownership?
CPU and DMA may access the same memory at different times. Establish who owns the buffer, when transfer completes, and whether cache maintenance and barriers are required. volatile does not solve cache coherency or prevent reuse before completion.
E13. How do you design a ring buffer?
Define capacity, full/empty representation, producer and consumer ownership, and overflow policy. Index wraparound is only one part; concurrent publication of data and indices needs the target’s synchronization contract. A single-core ISR consumer still creates concurrency.
E14. When is a state machine preferable to blocking delays?
A state machine records progress and reacts to events while allowing other work between transitions. Define valid states, transition conditions and timeout handling. It does not automatically guarantee timing; scheduler latency and execution bounds still matter.
E15. How should a watchdog be serviced?
Service it only when the system has demonstrated required progress, not blindly inside every timer interrupt. Define recovery behavior and capture diagnostic state where safe. A watchdog cannot correct a design that continually feeds it while the application is stuck.
E16. How do you debounce a switch?
Sample over a specified stable interval or use a documented hardware filter, accounting for the required response time. Test press, release, repeated bounce and long holds. A fixed delay in an interrupt handler is usually a poor default because it blocks other work.
E17. What distinguishes UART, SPI and I2C?
UART is typically asynchronous serial with agreed framing; SPI uses a controller-supplied clock and device-select conventions; I2C uses addressed devices and open-drain signaling with pull-ups. Pin voltage, bus speed and transaction details are device-specific; language code alone does not establish electrical compatibility.
E18. How do you reason about a wrapping timer?
Unsigned subtraction can measure elapsed ticks modulo the timer type’s range when the real elapsed interval is less than one full wrap and sampling is frequent enough. Deadline-ordering idioms often impose tighter half-range constraints. State the assumptions rather than mixing arbitrary signed casts into timing code.
E19. What can host-based tests verify?
Pure parsing, state transitions, checksum logic, buffer bounds and algorithm results can be tested with mocks or simulated inputs. Host tests do not validate real interrupts, register side effects, flash timing, power behavior, or signal integrity. Keep hardware-in-the-loop checks separate.
E20. What would you check in a firmware fault report?
Record firmware/build identity, reset cause, fault status, stack information and triggering input using a safe diagnostic path. Reproduce on the stated board and toolchain, inspect ownership and boundaries, and test recovery. Never treat one host run as proof the fault cannot occur on hardware.
Host-only bit-mask exercise
This program changes an ordinary unsigned integer, not a hardware register. It limits bit positions to 0–7 and returns 0 without changing the object for an invalid position. It demonstrates masks only: it has no ISR synchronization or memory-mapped I/O claim.
#include <stdio.h>
int update_bit(unsigned int *value, unsigned int bit, int enabled) {
if (value == NULL || bit > 7) return 0;
unsigned int mask = 1u << bit;
if (enabled) *value |= mask;
else *value &= ~mask;
return 1;
}
int main(void) {
unsigned int flags = 0;
if (!update_bit(&flags, 3, 1)) return 1;
printf("Set bit 3: %u\n", flags);
if (!update_bit(&flags, 3, 0)) return 1;
printf("Clear bit 3: %u\n", flags);
return 0;
}
Run host-only bit masks online
Expected output
Reference output for the displayed program, not a live execution result.
Set bit 3: 8
Clear bit 3: 0
Try starting with flags = 255, clearing bit 3 (247), then setting it (255). Test every permitted bit and reject bit 8 before shifting. Do not copy this function to a write-one-to-clear register: that peripheral needs a different access sequence. A device driver also needs the documented width and alignment of each access.
Interview follow-up exercise
Sketch a sensor task that owns a DMA receive buffer. State when ownership moves to DMA, which completion event returns it, what happens if the next sample arrives early, and when cache maintenance is required. A strong answer names the assumptions rather than treating volatile as a complete concurrency solution.
The online compiler runs hosted examples, not board firmware. There is no simulated physical device, register map, interrupt timing test or hardware certification on this page. Use the MCQ practice for language fundamentals and a real target/debug probe for firmware validation.