Programming · 55 pages
- C language — 15 lessonstutorial
- Lesson 1 — Hello, C
- Lesson 2 — Types & literals
- Lesson 3 — Expressions & operators
- Lesson 4 — Control flow
- Lesson 5 — Functions
- Lesson 6 — Arrays
- Lesson 7 — Pointers
- Lesson 8 — Strings
- Lesson 9 — Structs & unions
- Lesson 10 — Dynamic memory
- Lesson 11 — Preprocessor
- Lesson 12 — Multi-file projects
- Lesson 13 — Standard library
- Lesson 14 — Undefined behavior
- Lesson 15 — Modern C (C11/17/23)
- C++ programming — 15 lessonstutorial
- Lesson 1 — Hello, C++
- Lesson 2 — References & namespaces
- Lesson 3 — Classes & RAII
- Lesson 4 — Inheritance & polymorphism
- Lesson 5 — Templates
- Lesson 6 — STL containers
- Lesson 7 — Iterators & algorithms
- Lesson 8 — Smart pointers
- Lesson 9 — Move semantics
- Lesson 10 — Lambdas
- Lesson 11 — Error handling
- Lesson 12 — Concurrency
- Lesson 13 — Modules (C++20)
- Lesson 14 — Modern C++23
- Lesson 15 — C++ on Cortex-M
- Bare-metal C tutorial — 10 lessonsembedded
- Lesson 1 — Toolchain setup
- Lesson 2 — Bare-metal blink
- Lesson 3 — Registers in C
- Lesson 4 — Memory map
- Lesson 5 — Linker script
- Lesson 6 — Interrupts & ISRs
- Lesson 7 — Bit patterns
- Lesson 8 — Fixed-point math
- Lesson 9 — State machines
- Lesson 10 — Ring buffers + DMA
- Embedded C patterns
- volatile & memory-mapped IO
- CMSIS-Core
- CMSIS-DSP
- Linker scripts
- Startup & vector table
- C++ on Cortex-M
- Rust on Cortex-Mmodern
- Inline assembly
- Bare-metal libc & newlib-nano
- Bootloaders & DFU
- OTA update flow
C++ programming tutorial — from C-with-classes to modern C++23
A 15-lesson hands-on tutorial taking you through classes, RAII, templates, the STL, smart pointers, move semantics, lambdas, modules, and modern C++23. Built for C programmers and embedded engineers.
C++ is the most misunderstood language in the embedded world. People who learned it from a 2003 textbook remember iostream, multiple inheritance, RTTI, exceptions, and a fat runtime — and they refuse to touch it. People who learned it from a 2019 talk remember constexpr, ranges, concepts, and zero-overhead abstractions — and they cannot imagine why anyone would still write C. The truth lives between the two, and the difference comes down to which subset of the language you actually use.
This tutorial teaches the modern subset. The features that earn their keep: classes and RAII, templates, the STL containers you will actually reach for, smart pointers, move semantics, lambdas, ranges, and the C++23 additions like std::expected. It skips the historical baggage you can safely ignore: iostream formatting machinery, RTTI, exceptions on small targets, multiple inheritance soup, and the SFINAE tricks that concepts replaced.
By the end you will be able to read modern C++ codebases, write small libraries, use the STL without surprises, and — in the final lesson — apply what you learned to a Cortex-M target with arm-none-eabi-g++, knowing exactly which features cost what.
At a glance
- Target
- Portable C++23 (or C++20 with explicit fallbacks for ranges, concepts, modules)
- Hardware required
- None — runs on any host (Linux, macOS, Windows). Lesson 15 connects to Cortex-M.
- Software
- Any C++23-aware compiler: gcc 13+, clang 17+. We use g++ -std=c++23 -Wall -Wextra -Wpedantic.
- Time investment
- Approximately 25-35 hours total — 90-120 minutes per lesson
- Prerequisites
- Basic C (pointers, structs, headers) or fluency in another statically typed language. No prior C++ required.
- You will write
- About 3000 lines of C++ across 15 short, self-contained programs
- Output
- Working programs covering classes, RAII, templates, STL, smart pointers, move semantics, lambdas, ranges, modules, and an embedded-flavoured capstone
Philosophy
Three rules govern every lesson.
Use the features that pay for themselves at compile time. Templates, constexpr, concepts, and the type system are free at runtime — they cost compile time and they buy you safety. Use them liberally.
Be skeptical of features that pay at runtime. Virtual functions, std::function, std::shared_ptr, exceptions, and dynamic allocation all have costs that show up in your final binary and your worst-case execution time. Use them when you need polymorphism, ownership counting, or error propagation that the alternatives cannot give you — not because the textbook said you should.
Embedded relevance is a callout, not a detour. Every lesson has a "Embedded callout" section that says what changes when you target a Cortex-M with no heap, no exceptions, and a 100 KB flash budget. Most C++ features survive that constraint with minor tweaks. A few do not. You will know which by lesson 8.
How this differs from the reference page
/docs/programming/cpp/ is the reference: a flat list of C++ features with embedded-flavoured advice on each, suitable for someone who already knows C++ and wants to know what to use on Cortex-M. It does not teach the language; it filters it for firmware engineers.
This tutorial is the course: an ordered 15-lesson path from "I know C, what does C++ add?" to "I can write a templated, RAII-managed, move-aware library and ship it on bare metal." Read this first. After lesson 15, the reference page becomes a quick lookup for any feature you forgot. The two are paired: tutorial for learning, reference for living.
The 15 lessons
| Core | Arch | Pipe | DMIPS | FPU | DSP | MPU | TZ | MVE | Notes |
|---|---|---|---|---|---|---|---|---|---|
| Cortex-M0 | ARMv6-M | 3-stage | 0.84/MHz | — | Subset of Thumb-2. | ||||
| Cortex-M0+ | ARMv6-M | 2-stage | 0.95/MHz | — | Single-cycle I/O port. | ||||
| Cortex-M23 | ARMv8-M Baseline | 2-stage | 0.99/MHz | — | Secure & non-secure worlds. | ||||
| Cortex-M3 | ARMv7-M | 3-stage | 1.25/MHz | — | The classic mid-range core. | ||||
| Cortex-M33 | ARMv8-M Mainline | 3-stage | 1.50/MHz | SP | Used in nRF53, STM32L5/U5. | ||||
| Cortex-M4 | ARMv7E-M | 3-stage | 1.25/MHz | SP | Most popular general-purpose MCU core. | ||||
| Cortex-M55 | ARMv8.1-M | 4-stage | 1.6/MHz | SP/DP | 4–5× DSP/ML uplift vs. M4. | ||||
| Cortex-M7 | ARMv7E-M | 6-stage | 2.14/MHz | SP/DP | Used in i.MX RT, STM32H7. | ||||
| Cortex-M85 | ARMv8.1-M | 7-stage | 3.0/MHz | SP/DP | i.MX RT700, Renesas RA8. |
This page covers part 1: the landing page and lessons 1 through 8. Lessons 9 through 15 live in parts 2 and 3 of the tutorial.
How to use this tutorial
Four rules.
-
Read in order. Each lesson assumes the last. Lesson 4 (inheritance) makes no sense without lesson 3 (classes). Lesson 7 (algorithms) assumes the containers from lesson 6. The dependencies are real and they are dense.
-
Type the code. Every code block in this tutorial is real, compileable, and short. Type it into a file, compile with
g++ -std=c++23 -Wall -Wextra -Wpedantic, and run it. Reading C++ from a webpage and never compiling is the most common way to fool yourself into thinking you have learned C++. -
Do the exercises before reading the answers. Two or three exercises end each lesson. Answers are in
<Callout type="spec">blocks below them. Skipping the exercises and reading the answers feels efficient and is the slowest way to learn. -
Use the warnings.
-Wall -Wextra -Wpedanticcatches real bugs. When the compiler complains, read the message. C++ compiler errors look ugly but they are usually right. The first 20 you decode by hand will earn you a sense for the next 200.
What you will not learn here
This tutorial deliberately omits:
- Multiple inheritance and virtual inheritance beyond a one-paragraph mention. They exist; they are rarely the right answer; the patterns that justify them (mixins, interface inheritance with default implementations) are better served by composition plus templates.
- The full template metaprogramming toolkit. SFINAE,
std::enable_if, tag dispatch — concepts (C++20) replaced 90% of this. We mention the old names so you can read existing code, and move on. - C++ exceptions as the primary error model. We cover them in lesson 11 alongside the alternatives (
std::optional,std::expected). For embedded targets, exceptions are usually off. - Boost and other large external libraries. We stick to the standard library so the lessons compile anywhere
g++runs.
If you need any of these later, the C++ Programming Language reference (Stroustrup) and cppreference.com are exhaustive. This tutorial gets you to the point where those references are useful.
Compiler setup, in 30 seconds
On macOS:
brew install gcc
g++-14 --versionOn Linux:
sudo apt install g++-13 # Ubuntu 24.04 has g++-13; 24.10 has g++-14
g++ --versionOn Windows: install MSYS2 and pacman -S mingw-w64-ucrt-x86_64-gcc, or use WSL.
Every example in this tutorial compiles with:
g++ -std=c++23 -Wall -Wextra -Wpedantic -O2 file.cpp -o fileIf your compiler does not support -std=c++23, fall back to -std=c++20. Lessons 13 and 14 will then need adjustments noted inline. clang++ works identically — replace g++ with clang++ in every command.
Cross-references
- C tutorial — the 10-lesson bare-metal C tutorial. If you do not yet know C confidently, start there.
- C++ on Cortex-M — the reference page. Use it after this tutorial as a lookup for embedded-specific advice.
- Bare-metal C tutorial — register-level C on STM32. Lesson 15 of this tutorial connects back to it.
- GCC flags reference — every flag in our build commands explained.
Start with Lesson 1 — Hello, C++.