Course contentsShow
← Embedded Systems & Computer Architecture
Lesson 427 of 9366. Embedded Software Construction and ToolchainsFree lesson

Preprocessing Source Code into Translation Units

You will learn how the preprocessor resolves macros, includes header files, and handles conditional directives to prepare pure C code.

In this lesson, you will learn how the C preprocessor acts as the "first pass" of the compilation process, transforming your human-readable source files into a pure, consolidated translation unit that the compiler can actually understand.

The Preprocessing Stage

Before the compiler parses your syntax to generate machine code, it must handle directives—lines starting with a #. The preprocessor performs a text-based manipulation of your .c files to resolve these directives. Think of it as a specialized text editor that cleans up the "meta-instructions" left in your code.

Core Preprocessor Tasks

  1. File Inclusion: When you write #include "hardware_config.h", the preprocessor physically copies the entire contents of that header file and pastes it directly into your source file. It repeats this recursively, building a single, massive stream of code.
  2. Macro Expansion: It performs text replacement for defined macros. If you have #define BUFFER_SIZE 256, every instance of BUFFER_SIZE in your code is swapped for 256 before the compiler ever sees it.
  3. Conditional Compilation: This is vital for embedded systems. Using #ifdef and #ifndef, you can instruct the preprocessor to include or exclude blocks of code based on your build configuration (e.g., compiling different drivers for a STM32F4 versus an STM32F7 target).

A Concrete Illustration

Imagine this snippet in your driver.c:

#define MAX_RETRY 5
#ifdef DEBUG_MODE
    #define LOG(x) printf(x)
#else
    #define LOG(x)
#endif

int status = MAX_RETRY;
LOG("System Initialized");

If DEBUG_MODE is not defined, the preprocessor strips away the LOG macro and turns the code into:

int status = 5;
; // The LOG line effectively disappears

The resulting file, now devoid of all # directives and macros, is known as a translation unit. This represents the complete code set for a specific module that the compiler will now analyze for semantic correctness and translate into assembly language.

Key Takeaway: The preprocessor performs structural text manipulation—including header injection, macro expansion, and conditional filtering—to flatten your project's modular files into a single, comprehensive translation unit for the compiler.