Interview questions · Tech stack

Embedded C Interview Questions & Answers (2026)

These interviews test your grasp of low‑level programming, memory management, concurrency, and hardware interaction. Demonstrate clear reasoning, explain trade‑offs, and show familiarity with toolchains and debugging. Focus on concrete examples, safety considerations, and performance impacts to convince interviewers you can write reliable embedded code.

22 questions · updated Aug 29, 2026

Quick facts

Typical roundsPhone screen, technical coding, hardware design discussion, and on‑site debugging
Core topicsPointers, ISR, RTOS basics, peripheral registers, compiler optimizations
Preferred languagesC (C99/C11), occasional assembly for critical sections
Common toolsGCC, IAR, Keil, JTAG/SWD debuggers, static analysis
Success metricAbility to write safe, deterministic code that meets memory and timing constraints

Questions

Beginner

What is the difference between volatile and const qualifiers in embedded C?

volatile tells the compiler that a variable can change outside the program flow, preventing optimizations that assume stability; const indicates read‑only data, allowing the compiler to place it in flash or ROM. Interviewers expect you to explain that volatile is essential for memory‑mapped registers and ISR‑shared variables, while const helps reduce RAM usage and can enable compile‑time checks. A strong answer mentions both qualifiers together for read‑only hardware registers, e.g., const volatile uint32_t *TIM = (const volatile uint32_t *)0x40000000.

const volatile uint32_t *TIM = (const volatile uint32_t *)0x40000000;
Texas InstrumentsNXP

How do you safely share a variable between an ISR and main code?

Use a volatile variable and protect access with either disabling interrupts around critical sections or employing atomic operations if the MCU supports them. Explain that reading/writing must be atomic; for multi‑byte data, disable the interrupt, copy the value, then re‑enable. Mention that using a flag (e.g., a bit in a status register) is preferred over busy‑waiting. A strong candidate also discusses priority inversion and the importance of keeping ISR short.

volatile uint8_t flag;
void ISR(void) { flag = 1; }
void main(void) { while (!flag); flag = 0; }
STMicroelectronics

Explain the role of the linker script in embedded development.

The linker script maps sections (.text, .data, .bss, .rodata) to physical memory addresses, defining where code, constants, and variables reside. Interviewers want you to note that it ensures flash‑resident code, RAM allocation for initialized data, and placement of interrupt vectors at the correct address. A solid answer also mentions alignment constraints, memory protection units, and how modifying the script can relocate critical routines to faster memory or reserve space for bootloaders.

Microchip

What are the implications of using recursion on a microcontroller with limited stack?

Recursion consumes stack each call, which can quickly exceed limited RAM, leading to overflow and system crash. In embedded contexts, recursion is discouraged unless depth is bounded and analyzed. Explain that tail‑call optimization is not guaranteed, so each call adds overhead. A strong answer also suggests converting recursive algorithms to iterative ones and using static buffers when possible.

STMicroelectronics

Explain the difference between static and dynamic memory allocation in embedded C.

Static allocation reserves memory at compile time, guaranteeing placement and eliminating fragmentation, which is ideal for deterministic systems. Dynamic allocation (malloc/free) occurs at runtime, introducing heap fragmentation and unpredictable latency, making it risky for real‑time constraints. Interviewers expect you to state that many safety‑critical codebases forbid dynamic allocation after initialization. A strong candidate mentions using a fixed‑size memory pool as a compromise.

NXP

Why is it important to align structures to word boundaries in embedded systems?

Misaligned accesses may cause extra cycles, bus faults, or hardware exceptions on many MCUs. Aligning structures ensures each member resides at an address the processor can fetch efficiently, preserving deterministic timing. Interviewers look for knowledge that the compiler can add padding, and that pragma pack directives should be used cautiously. A strong candidate also notes that DMA engines often require word‑aligned buffers.

STMicroelectronics

Intermediate

What is stack overflow in an embedded system and how can you prevent it?

Stack overflow occurs when a function call hierarchy exceeds the allocated stack size, corrupting adjacent memory and causing unpredictable behavior. Prevent it by analyzing worst‑case stack usage, using static analysis tools, and adding guard bytes or canaries. Explain that recursion is rarely used; if needed, limit depth and check return values. A strong answer also references configuring the linker script to allocate sufficient stack and enabling runtime stack checking if the toolchain supports it.

Qualcomm

Describe how you would implement a debounce algorithm for a mechanical button.

Use a timer‑based approach: sample the button at a fixed interval, require N consecutive identical readings before changing state. This filters out spurious transitions caused by contact bounce. Mention that a simple state machine with a counter resets on each change, and that the debounce period should be chosen based on the hardware spec (typically 5‑20 ms). A strong candidate may also discuss using hardware filters or the MCU’s built‑in debounce peripheral if available.

if (button == last_state) { count++; if (count >= DEBOUNCE_THRESHOLD) stable_state = button; } else { count = 0; }
Bosch

How does the compiler optimize away unused variables and why is this problematic for hardware registers?

Compilers remove variables that are never read or written to reduce code size. For hardware registers, this can discard necessary side‑effects, breaking functionality. Explain that marking such variables as volatile prevents removal, ensuring each access generates a load/store. A strong answer also notes that using the register’s address directly without a volatile qualifier can lead to the compiler caching the value, causing stale reads.

Infineon

What are the trade‑offs between using a polling loop versus an interrupt for sensor data acquisition?

Polling consumes CPU cycles continuously, leading to higher power usage and potentially missed events if the loop is too slow. Interrupts react instantly, saving power and guaranteeing timely handling, but introduce context‑switch overhead and require careful ISR design to avoid latency. A strong answer weighs deterministic latency, power budget, and system complexity, recommending interrupts for low‑power or time‑critical designs and polling for simple, non‑time‑sensitive tasks.

Analog Devices

How does the __builtin_expect() macro help with performance in embedded code?

It informs the compiler which branch is likely, allowing better instruction pipelining and branch prediction. For example, error handling paths are marked as unlikely, so the hot path remains in the instruction cache. Interviewers look for awareness that this is a GCC extension and that misuse can degrade performance if predictions are wrong. A strong answer also notes that the effect is modest on simple MCUs without sophisticated branch predictors.

Qualcomm

What is the purpose of the 'restrict' keyword in pointer declarations?

restrict tells the compiler that for the lifetime of the pointer, the object it points to will not be accessed through any other pointer. This enables more aggressive optimizations like loop unrolling and vectorization. In embedded code, it can reduce memory traffic for buffer copies. Interviewers expect you to mention that misuse leads to undefined behavior, so it should only be used when you can guarantee non‑aliasing.

Intel

How would you handle endianness conversion when communicating with a big‑endian peripheral?

Use byte‑swap functions (e.g., __builtin_bswap16/32) or manually shift bytes to reorder them before writing to or after reading from the peripheral. Explain that the MCU’s native endianness must be known, and that network‑order functions (htons, htonl) are often used for portability. A strong answer also mentions aligning data structures to avoid misaligned accesses during conversion.

Microchip

How does the compiler's -fno-common flag affect variable definitions?

-fno-common forces the compiler to place tentative definitions in the data section rather than allowing multiple definitions to be merged by the linker. This catches duplicate global variables early, preventing subtle bugs. Interviewers expect you to explain that enabling this flag improves link‑time safety, especially in large embedded projects where multiple translation units may unintentionally declare the same symbol.

Microchip

Advanced

Explain the concept of memory‑mapped I/O and its implications for pointer arithmetic.

Memory‑mapped I/O treats peripheral registers as addresses in the address space, accessed via pointers. Pointer arithmetic must respect the register width and alignment; adding 1 to a uint32_t pointer advances by 4 bytes, not 1. Interviewers expect you to discuss that reads/writes may have side‑effects, so each access must be volatile and correctly aligned. A strong candidate also mentions that some MCUs require specific bus widths, and misaligned accesses can cause faults or performance penalties.

volatile uint32_t *UART_DR = (volatile uint32_t *)0x4000C000;
UART_DR[0] = 'A'; // writes to data register
Renesas

How would you implement a lock‑free circular buffer for UART communication?

Use head and tail indices stored in volatile variables. The producer writes data and advances head, wrapping around with modulo buffer size; the consumer reads from tail and advances similarly. Ensure that only one context updates each index to avoid race conditions. Explain that checking (head + 1) % size != tail prevents overflow, and that the buffer size should be a power of two for efficient masking. A strong answer also mentions disabling interrupts only for the minimal critical section if needed.

volatile uint16_t head, tail;
uint8_t buf[BUF_SIZE];
void put(uint8_t c){ uint16_t next = (head+1)&MASK; if(next!=tail){ buf[head]=c; head=next; } }
uint8_t get(void){ if(tail==head) return EMPTY; uint8_t c=buf[tail]; tail=(tail+1)&MASK; return c; }
Silicon Labs

What is the purpose of the __attribute__((section(".my_section"))) directive?

It tells the compiler to place a function or variable into a specific linker section, allowing custom placement in memory. This is useful for locating critical code in fast RAM, bootloader sections, or reserved flash pages. Interviewers look for understanding of how the linker script must define the named section and that the attribute works with GCC and compatible toolchains. A strong answer also notes potential alignment issues and the need to keep the section size within allocated memory.

NVIDIA

Describe how you would use a watchdog timer to recover from a software hang.

Configure the watchdog with a timeout longer than the longest expected task, then periodically reset (kick) it in the main loop. If the software hangs, the watchdog expires and triggers a system reset, returning the MCU to a known state. Explain that the watchdog should be enabled early in boot, that the kick must be atomic, and that critical sections should not block the kick for longer than the timeout. A strong candidate also mentions using the watchdog to capture diagnostic info before reset.

Freescale

How do you ensure deterministic execution time for a critical function?

Eliminate dynamic memory allocation, avoid function calls with unknown depth, and use fixed‑size loops. Compile with optimization flags that prevent instruction reordering (e.g., -O0 for timing analysis) and place the function in RAM for faster access if needed. Mention measuring worst‑case execution time (WCET) with cycle‑accurate simulators or hardware trace, and that using inline assembly can guarantee instruction count. A strong answer also discusses aligning code to cache lines and disabling interrupts during execution.

Honeywell

What are the advantages and disadvantages of using a real‑time operating system (RTOS) in embedded projects?

Advantages include deterministic task scheduling, priority management, and built‑in synchronization primitives, which simplify complex designs. Disadvantages are increased RAM/ROM footprint, added latency from context switches, and learning curve. Interviewers expect you to discuss that an RTOS is justified when concurrency, timing, and modularity outweigh resource constraints, and that careful configuration (tick rate, stack sizes) mitigates overhead.

Texas Instruments

Explain how you would perform a firmware update over UART without corrupting the existing application.

Implement a bootloader that resides in a protected flash region and validates incoming firmware via checksum or cryptographic signature. The bootloader writes the new image to a separate flash bank while the application runs, then verifies integrity before swapping execution. Discuss using double‑bank flash, atomic sector erases, and ensuring the bootloader cannot be overwritten. A strong answer also mentions fallback mechanisms if verification fails.

NXP

What is a memory barrier and when would you use it in embedded C?

A memory barrier prevents the compiler or CPU from reordering memory accesses across the barrier, ensuring proper sequencing of reads/writes to shared hardware registers or between cores. Use it when interacting with peripherals that require a specific order, such as clearing an interrupt flag after reading a status register. Explain that GCC provides __sync_synchronize() or asm volatile ("":::"memory") and that hardware may also provide explicit barrier instructions.

Qualcomm

Common mistakes

  • Omitting volatile on hardware registers, leading to optimized‑away accesses
  • Using recursion without stack analysis, causing overflow
  • Relying on dynamic memory allocation in time‑critical code
  • Disabling interrupts for too long, impacting system responsiveness
  • Misaligning buffers for DMA, resulting in transfer errors
  • Assuming compiler will automatically handle endianness

Study plan

  1. Review C language fundamentals with emphasis on qualifiers, pointer arithmetic, and memory layout
  2. Practice writing ISR‑safe code and volatile usage on a development board
  3. Study linker scripts, memory sections, and toolchain options for size and speed
  4. Implement common patterns: debounce, circular buffers, watchdog handling, and bootloader flow
  5. Run static analysis and WCET measurements on sample projects
  6. Mock interview: answer each question aloud, focusing on reasoning and trade‑offs

FAQ

Do I need to know assembly for an Embedded C interview?

Basic assembly knowledge is often expected to explain low‑level timing, interrupt handling, and register access. You don't need to write full routines, but you should understand how the compiler translates critical sections and be able to read simple assembly snippets.

How much emphasis is placed on RTOS concepts?

Many embedded roles use an RTOS, so interviewers probe your understanding of tasks, priorities, and synchronization primitives. Be ready to discuss context‑switch overhead, priority inversion, and when a bare‑metal approach is preferable.

What tools should I be familiar with before the interview?

Know GCC or IAR command‑line options, how to read linker maps, use a debugger (JTAG/SWD), and interpret trace logs. Familiarity with static analysis tools like Cppcheck or MISRA checkers is a plus.

Is it important to know hardware peripherals?

Yes. Interviewers often ask about configuring UART, SPI, or timers. Demonstrate that you can set registers, calculate baud rates, and handle edge cases like overrun errors.

How should I talk about performance optimization?

Focus on concrete trade‑offs: explain why you would use inline functions, loop unrolling, or place code in RAM. Mention measuring cycles, using compiler reports, and ensuring deterministic timing for critical paths.

Related

Ready for your next interview?

Download MiPrep AI. Load your resume and the job description. Show up ready.

Free tier · No credit card · macOS 14+ · Windows 10+

Free tier · No credit card · Runs on your Mac or Windows machine