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 language tutorial — for embedded engineers
A 15-lesson hands-on tutorial taking you from hello world through pointers, memory, the preprocessor, the standard library, and modern C11/17/23. Built for people who already program and want to learn C properly.
Most people who pick up C in 2026 are not learning their first language. They already know Python or JavaScript or Java or Go, they can read a for loop without thinking, and they understand what a function is. What they do not have — and what C demands — is a model of the machine. C is the language where every variable has a known address, every pointer is a literal number, every byte of memory is yours to manage, and the compiler will happily generate code that compiles, links, runs once, and then corrupts itself on the second iteration because you wrote past the end of an array.
This tutorial teaches C as it actually is. Not as a friendlier Python with semicolons, not as a stripped-down Java, but as a thin layer over the silicon — which is exactly what makes it the right language for firmware, kernels, embedded systems, and anywhere else you need to know what the machine is doing.
Who this is for
You already program. You have shipped code in at least one other language. You understand what a variable, a function, a loop, and a struct or class are at a conceptual level. You may have read C code before (it is hard to avoid in 2026) but never written it confidently. You are probably here because:
- You are moving into embedded or firmware work and the job uses C every day.
- You want to read the Linux kernel, Redis, SQLite, CPython, or your favourite open-source project without bouncing off the syntax.
- You are tired of "C is dangerous" advice from people who have never written a memcpy and you want to form your own opinion.
- You are about to take on a course or project where C is the medium, and you want to be productive on day one instead of week three.
The tutorial does not start at zero. We will not define what a variable is. We will, however, carefully explain everything that makes C different from a managed language: manual memory, undefined behavior, pointers as first-class objects, integer width quirks that bite at runtime, the absence of bounds checking, and a type system that lets you cast a pointer to almost anything if you are willing to ask.
Philosophy
Learn the language properly before you touch hardware.
That is the whole pitch. There are two common failure modes for people learning C for embedded work.
The first is to dive straight into a vendor SDK — Arduino, STM32Cube, ESP-IDF — and copy example code. You get an LED blinking in 20 minutes, you feel productive, and then six weeks later you cannot debug a stuck DMA stream because you do not understand pointers well enough to read the source.
The second is to learn C through an academic textbook that spends three weeks on "what is a variable" before getting to anything useful. The pace is wrong for someone who already programs, and the examples (linked lists of student records!) bear no resemblance to what you will actually write.
This tutorial sits in the middle. We move fast where the reader's existing knowledge applies (control flow, expressions, basic functions) and slow where C is genuinely different from what you already know (pointers, memory, undefined behavior, the preprocessor, the standard library quirks, integer promotion rules). Every lesson has real, compileable code you can run on your laptop today, plus exercises with answers so you can verify your understanding.
After you finish this tutorial, you should be ready for the bare-metal embedded C tutorial, which takes the C language you have learned and applies it to an ARM Cortex-M microcontroller — volatile, memory-mapped I/O, linker scripts, interrupt handlers, DMA. That tutorial assumes you already know C. This one is how you get there.
At a glance
- Target
- Portable C17 — your host PC, any operating system
- Hardware required
- None. A laptop with any C compiler is enough.
- Software
- gcc (recommended), clang, or MSVC. We use gcc syntax in flags.
- Time investment
- Approximately 20-30 hours total — 90-120 minutes per lesson
- Prerequisites
- Comfortable in at least one other language (Python, JavaScript, Java, Go, Rust, C#, or similar)
- Output
- Solid working knowledge of the C language up to C17, with a preview of C23 features
- Standard
- C17 throughout, with C11 features marked, C23 covered in the final lesson
Required tools
Any modern C compiler will do. The tutorial uses gcc invocations for examples, but every program compiles unchanged with clang and (with minor flag syntax differences) MSVC.
- Linux:
sudo apt install build-essentialor your distribution's equivalent. You get gcc, make, and gdb. - macOS: install the Xcode Command Line Tools (
xcode-select --install). That gives you clang aliased asgcc, plus make and lldb. The lessons work identically. - Windows: the recommended path is WSL2 with Ubuntu, then follow the Linux instructions. Native MinGW or MSVC also works, but every Stack Overflow answer assumes Linux paths and tooling, so WSL saves you grief.
You also want a text editor that knows C syntax: VS Code with the C/C++ extension, Neovim with treesitter, CLion, or whatever you already use. Avoid IDE-only build systems for this tutorial — we want to see the compiler command line.
To confirm everything works:
$ gcc --version
gcc (Ubuntu 13.2.0-23ubuntu4) 13.2.0
$ echo 'int main(void){return 0;}' > t.c && gcc t.c -o t && ./t && echo ok
okIf that prints ok, you are ready for lesson 1.
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. |
How to use this tutorial
Three rules. They sound boring; they are the difference between absorbing the material and forgetting it.
-
Read in order. Lessons assume previous ones. Lesson 7 (pointers) uses array decay from lesson 6. Lesson 10 (dynamic memory) builds on lesson 9 (structs). Lesson 14 (undefined behavior) references almost every prior lesson.
-
Type the code. Compile it. Run it. Every code block in this tutorial is a complete, compileable C program (or a snippet that obviously belongs in one). When you read
printf("%d\n", x);, do not just nod — paste it into a file, compile, run, then change a value and see what changes. Friction is where the learning lives. -
Do the exercises before reading the answers. Each lesson ends with 2-3 exercises and answers in collapsible callouts. Try the exercise. Spend 15 minutes stuck on it. Then read the answer. The hour of struggle teaches more than the five minutes of reading.
Cross-references
- Bare-metal C tutorial — the natural next step. Apply your C to a Cortex-M microcontroller.
- Embedded C patterns — patterns used in firmware: volatile, packed, alignment, weak symbols.
- volatile and memory-mapped I/O — what volatile means at the silicon level.
- The C standard library on embedded — newlib, picolibc, what to use when malloc is off the table.
- C++ tutorial — when you are ready to add classes, RAII, and templates on top.
- GCC flags reference — every flag in our build commands explained.
Start with Lesson 1 — Hello, C.