Embedded C

Embedded C is not a separate language but C as it is actually written for microcontrollers and other resource-constrained hardware. The standard C language is the same, yet the constraints of embedded targets, no operating system to lean on, kilobytes rather than gigabytes of memory, and direct responsibility for hardware, shape a distinctive style. Mastering embedded C is largely about a handful of idioms that rarely matter on a desktop but are essential on a chip.

The most characteristic of these is the volatile qualifier on memory-mapped hardware registers. On a microcontroller, peripherals are controlled by reading and writing fixed memory addresses. The avr-libc manual explains that on AVR parts “the entire IO address space is made available as memory-mapped IO,” reachable with ordinary memory instructions. Because the value at such an address can change outside the program’s control, or because a write has a side effect on hardware, these locations are declared volatile to stop the compiler from optimizing the accesses away or reordering them. Forgetting volatile is one of the classic embedded bugs: code that works in a debug build mysteriously breaks when optimized.

Embedded C also leans on precise, fixed-width integer types. When a register is exactly eight or sixteen bits wide and every byte of RAM counts, the vague widths of plain int are a liability, so embedded code uses types of known size and signedness. Dynamic memory allocation is commonly avoided or banned outright: there may be no heap, and malloc’s unpredictable timing and fragmentation are unacceptable in a system that must run for years without rebooting. Memory is instead laid out statically, sized at build time, giving deterministic behavior.

In safety-critical fields these conventions are formalized into coding standards, the most influential being MISRA C. Developed by the MISRA Consortium and titled “Guidelines for the use of the C language in critical systems,” it was created to support the language requirements of the original 1994 MISRA automotive guidelines and has since spread far beyond cars into aerospace, medical devices, rail, and defense. MISRA C restricts C to a safer subset, forbidding constructs whose behavior is undefined, ambiguous, or error-prone, on the principle that what the standard permits is not always what a critical system should allow.

MISRA’s compliance model reflects how seriously this discipline is taken. Rules are classified as mandatory, required, or advisory; to claim compliance, all mandatory rules must be met and all required rules either met or covered by a formally recorded deviation. The standard does not just suggest good practice, it defines an auditable contract for how C may be used when lives or critical infrastructure depend on the code.

C endures as the dominant embedded language precisely because it is close to the metal: it maps cleanly onto registers and addresses, imposes little runtime overhead, and runs on processors too small for anything heavier. Embedded C is the accumulated craft of using that power without being cut by it.