Embedded C++
Modern C++ brings type safety and zero-cost abstractions to microcontrollers. Learn which features to use (classes, namespaces, references, constexpr, templates, enum class, RAII, std::array) and which to avoid or control (exceptions, RTTI, dynamic allocation, iostreams), plus virtual-function costs and compile-time peripheral configuration.
C++ is increasingly used in embedded products (Arduino, mbed, Zephyr C++ apps, automotive AUTOSAR Adaptive). Used carefully, it produces code as small and fast as C while catching more errors at compile time.
An analogy
Embedded C++ is like a professional toolbox where you leave the heavy power tools (exceptions, heap) in the van and use the precise hand tools (constexpr, templates) that add no weight.
Why C++?
Stronger typing (enum class, references), encapsulation (classes, namespaces), generic code (templates), compile-time computation (constexpr), and automatic cleanup (RAII) — with no runtime overhead when used carefully.
Features to restrict
Exceptions and RTTI add code size and unpredictable timing (compile with -fno-exceptions -fno-rtti). Avoid heap allocation (new/delete, std::vector growth) in real-time code; use std::array, static pools and placement new. Avoid iostream (huge).
Polymorphism
Virtual functions cost a vtable pointer per object and an indirect call — acceptable for drivers with multiple implementations. Static polymorphism (templates, CRTP) removes the indirection when types are known at compile time.
Standards and practice
MISRA C++ and AUTOSAR C++14 rules for safety-critical code; Embedded Template Library (ETL) for fixed-capacity containers; C++17/20 features (constexpr if, concepts, std::span) improve clarity.
Formulas
- Virtual dispatch cost:
RAM = objects × sizeof(void*) + ROM = classes × vtable size - Zero-cost abstraction:
Inline templates/constexpr → same machine code as hand-written C
Worked example: Virtual function overhead
Given: 100 sensor objects with virtual read(); 32-bit MCU
Find: RAM overhead.
- vptr = 4 bytes per object
- 100 × 4 = 400 bytes
Answer: 400 bytes RAM + one vtable per class in flash
Worked example: constexpr table
Given: Sine table of 256 entries computed with constexpr
Find: Runtime cost.
- Values computed by the compiler and stored in flash
Answer: Zero runtime computation, no RAM used
Type-safe GPIO with templates and RAII
#include <cstdint>
enum class Port : std::uintptr_t { A = 0x40020000, B = 0x40020400 };
template <Port P, unsigned Pin>
struct Gpio {
static_assert(Pin < 16, "pin out of range");
static constexpr std::uintptr_t base = static_cast<std::uintptr_t>(P);
static volatile std::uint32_t& reg(unsigned off) {
return *reinterpret_cast<volatile std::uint32_t*>(base + off);
}
static void set() { reg(0x18) = 1u << Pin; } // BSRR set
static void clear() { reg(0x18) = 1u << (Pin + 16); } // BSRR reset
};
using Led = Gpio<Port::A, 5>; // resolved entirely at compile time
class CriticalSection { // RAII: interrupts restored automatically
public:
CriticalSection() { __asm volatile("cpsid i"); }
~CriticalSection() { __asm volatile("cpsie i"); }
};
void blink_once() {
CriticalSection cs; // disabled here...
Led::set();
Led::clear();
} // ...re-enabled when cs goes out of scopeTemplate parameters fix the port and pin at compile time, so Led::set() compiles to a single store instruction. static_assert catches wrong pins before the code ever runs; RAII makes it impossible to forget re-enabling interrupts.
Common mistakes
- Wrong: Using std::vector push_back in ISRs. — Right: Use fixed-size containers and preallocated buffers.
- Wrong: Assuming C++ is always bigger than C. — Right: Measure — disable exceptions/RTTI and inline templates.
Applications
- HAL design: Type-safe driver interfaces.
- Automotive: AUTOSAR Adaptive C++14 applications.
- Frameworks: Arduino, mbed OS, Zephyr C++.
Key takeaways
- C++ can be zero-cost on MCUs.
- Prefer constexpr, templates, RAII, enum class.
- Avoid heap, exceptions, RTTI in RT code.
- Virtual = vptr + indirect call.
Going further
- CRTP: Curiously recurring template pattern for static polymorphism.
- ETL: Embedded Template Library containers.
- MISRA C++: Safety-critical coding rules.